diff options
| author | bors <bors@rust-lang.org> | 2024-01-26 06:59:26 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-01-26 06:59:26 +0000 |
| commit | fae15df5c60ccf0f9eaa96651c869d2c2001fddb (patch) | |
| tree | b452546913281a644984fff0862defd7ec76890e /src/tools | |
| parent | 9f4d1a41a6dccf00caace1e9fd20011d586d8b69 (diff) | |
| parent | 2318b0825cc2892a388b307d38389658f09ac3b6 (diff) | |
| download | rust-fae15df5c60ccf0f9eaa96651c869d2c2001fddb.tar.gz rust-fae15df5c60ccf0f9eaa96651c869d2c2001fddb.zip | |
Auto merge of #3280 - rust-lang:rustup-2024-01-26, r=RalfJung
Automatic Rustup
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/clippy/tests/ui/crashes/ice-6254.rs | 2 | ||||
| -rw-r--r-- | src/tools/clippy/tests/ui/crashes/ice-6254.stderr | 15 | ||||
| -rw-r--r-- | src/tools/clippy/tests/ui/modulo_one.rs | 3 | ||||
| -rw-r--r-- | src/tools/clippy/tests/ui/modulo_one.stderr | 8 | ||||
| -rw-r--r-- | src/tools/compiletest/src/header.rs | 3 | ||||
| -rw-r--r-- | src/tools/compiletest/src/header/tests.rs | 21 | ||||
| -rw-r--r-- | src/tools/miri/rust-version | 2 | ||||
| -rw-r--r-- | src/tools/miri/src/machine.rs | 54 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/intrinsics/mod.rs | 13 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/const-addrs.rs | 38 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/intrinsics.rs | 15 |
11 files changed, 133 insertions, 41 deletions
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs index 2ae426cf789..8af60890390 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs @@ -11,8 +11,6 @@ fn main() { // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) match FOO_REF_REF { FOO_REF_REF => {}, - //~^ ERROR: to use a constant of type `Foo` in a pattern, `Foo` must be annotated - //~| NOTE: for more information, see issue #62411 <https://github.com/rust-lang/ru Foo(_) => {}, } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr deleted file mode 100644 index 7a34e6cceee..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/ice-6254.rs:13:9 - | -LL | FOO_REF_REF => {}, - | ^^^^^^^^^^^ - | - = 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 #62411 <https://github.com/rust-lang/rust/issues/62411> - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - = note: `-D indirect-structural-match` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(indirect_structural_match)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/modulo_one.rs b/src/tools/clippy/tests/ui/modulo_one.rs index c1dbe9d9a87..c332a15f157 100644 --- a/src/tools/clippy/tests/ui/modulo_one.rs +++ b/src/tools/clippy/tests/ui/modulo_one.rs @@ -33,7 +33,6 @@ fn main() { INT_MIN % NEG_ONE; //~^ ERROR: this operation will panic at runtime //~| ERROR: any number modulo -1 will panic/overflow or result in 0 - // ONLY caught by rustc + // Not caught by lint, we don't look into static items, even if entirely immutable. INT_MIN % STATIC_NEG_ONE; - //~^ ERROR: this operation will panic at runtime } diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr index cc211ab6cd3..06bbb0f5d9a 100644 --- a/src/tools/clippy/tests/ui/modulo_one.stderr +++ b/src/tools/clippy/tests/ui/modulo_one.stderr @@ -12,12 +12,6 @@ error: this operation will panic at runtime LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow -error: this operation will panic at runtime - --> $DIR/modulo_one.rs:37:5 - | -LL | INT_MIN % STATIC_NEG_ONE; - | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow - error: any number modulo 1 will be 0 --> $DIR/modulo_one.rs:8:5 | @@ -57,5 +51,5 @@ error: any number modulo -1 will panic/overflow or result in 0 LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e70e01e8757..ff907152ca9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1109,9 +1109,6 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { } fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { - if config.system_llvm && line.starts_with("no-system-llvm") { - return IgnoreDecision::Ignore { reason: "ignored when the system LLVM is used".into() }; - } if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 8882f1582ac..c859e8acade 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -243,15 +243,6 @@ fn aux_build() { } #[test] -fn no_system_llvm() { - let config: Config = cfg().system_llvm(false).build(); - assert!(!check_ignore(&config, "// no-system-llvm")); - - let config: Config = cfg().system_llvm(true).build(); - assert!(check_ignore(&config, "// no-system-llvm")); -} - -#[test] fn llvm_version() { let config: Config = cfg().llvm_version("8.1.2").build(); assert!(check_ignore(&config, "// min-llvm-version: 9.0")); @@ -267,6 +258,18 @@ fn llvm_version() { } #[test] +fn system_llvm_version() { + let config: Config = cfg().system_llvm(true).llvm_version("17.0.0").build(); + assert!(check_ignore(&config, "// min-system-llvm-version: 18.0")); + + let config: Config = cfg().system_llvm(true).llvm_version("18.0.0").build(); + assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); + + let config: Config = cfg().llvm_version("17.0.0").build(); + assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); +} + +#[test] fn ignore_target() { let config: Config = cfg().target("x86_64-unknown-linux-gnu").build(); diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 62bef6d52d9..6624672775f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f6ee4bf3847277d6d6e2007ff664f8ea0895b11b +dd2559e08e1530806740931037d6bb83ef956161 diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 567ac6cff67..946887637ff 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -3,12 +3,14 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; +use std::collections::hash_map::Entry; use std::fmt; use std::path::Path; use std::process; use either::Either; use rand::rngs::StdRng; +use rand::Rng; use rand::SeedableRng; use rustc_ast::ast::Mutability; @@ -45,6 +47,11 @@ pub const SIGRTMIN: i32 = 34; /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`) pub const SIGRTMAX: i32 = 42; +/// Each const has multiple addresses, but only this many. Since const allocations are never +/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would +/// produce unbounded memory usage. +const ADDRS_PER_CONST: usize = 16; + /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { /// Extra data for the Borrow Tracker. @@ -65,12 +72,19 @@ pub struct FrameExtra<'tcx> { /// optimization. /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span` pub is_user_relevant: bool, + + /// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`]. + /// However, we don't want all frames to always get the same result, so we insert + /// an additional bit of "salt" into the cache key. This salt is fixed per-frame + /// so that within a call, a const will have a stable address. + salt: usize, } impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self; + let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = + self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) @@ -80,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self; + let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = + self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -552,6 +567,11 @@ pub struct MiriMachine<'mir, 'tcx> { /// The spans we will use to report where an allocation was created and deallocated in /// diagnostics. pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>, + + /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`) + /// that is fixed per stack frame; this lets us have sometimes different results for the + /// same const while ensuring consistent results within a single call. + const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx, Provenance>>>, } impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { @@ -677,6 +697,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { stack_size, collect_leak_backtraces: config.collect_leak_backtraces, allocation_spans: RefCell::new(FxHashMap::default()), + const_cache: RefCell::new(FxHashMap::default()), } } @@ -788,6 +809,7 @@ impl VisitProvenance for MiriMachine<'_, '_> { stack_size: _, collect_leak_backtraces: _, allocation_spans: _, + const_cache: _, } = self; threads.visit_provenance(visit); @@ -1345,6 +1367,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { catch_unwind: None, timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), + salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_CONST, }; Ok(frame.with_extra(extra)) @@ -1450,4 +1473,31 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None)); Ok(()) } + + fn eval_mir_constant<F>( + ecx: &InterpCx<'mir, 'tcx, Self>, + val: mir::Const<'tcx>, + span: Option<Span>, + layout: Option<TyAndLayout<'tcx>>, + eval: F, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + where + F: Fn( + &InterpCx<'mir, 'tcx, Self>, + mir::Const<'tcx>, + Option<Span>, + Option<TyAndLayout<'tcx>>, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + { + let frame = ecx.active_thread_stack().last().unwrap(); + let mut cache = ecx.machine.const_cache.borrow_mut(); + match cache.entry((val, frame.extra.salt)) { + Entry::Vacant(ve) => { + let op = eval(ecx, val, span, layout)?; + ve.insert(op.clone()); + Ok(op) + } + Entry::Occupied(oe) => Ok(oe.get().clone()), + } + } } diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index a1db7bf74f2..e34fb118f72 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -5,6 +5,7 @@ use std::iter; use log::trace; +use rand::Rng; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{ @@ -141,6 +142,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?; } + // We want to return either `true` or `false` at random, or else something like + // ``` + // if !is_val_statically_known(0) { unreachable_unchecked(); } + // ``` + // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). + "is_val_statically_known" => { + let [arg] = check_arg_count(args)?; + this.validate_operand(arg)?; + let branch: bool = this.machine.rng.get_mut().gen(); + this.write_scalar(Scalar::from_bool(branch), dest)?; + } + // Floating-point operations "fabsf32" => { let [f] = check_arg_count(args)?; diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs new file mode 100644 index 00000000000..6c14f0b679c --- /dev/null +++ b/src/tools/miri/tests/pass/const-addrs.rs @@ -0,0 +1,38 @@ +// The const fn interpreter creates a new AllocId every time it evaluates any const. +// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use +// we need to keep track of the base address for that AllocId, and the allocation is never +// deallocated. +// In Miri we explicitly store previously-assigned AllocIds for each const and ensure +// that we only hand out a finite number of AllocIds per const. +// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same +// stack frame, breaking this test. +//@compile-flags: -Zinline-mir=no +#![feature(strict_provenance)] + +const EVALS: usize = 256; + +use std::collections::HashSet; +fn main() { + let mut addrs = HashSet::new(); + for _ in 0..EVALS { + addrs.insert(const_addr()); + } + // Check that the const allocation has multiple base addresses + assert!(addrs.len() > 1); + // But also that we get a limited number of unique base addresses + assert!(addrs.len() < EVALS); + + // Check that within a call we always produce the same address + let mut prev = 0; + for iter in 0..EVALS { + let addr = "test".as_bytes().as_ptr().addr(); + if iter > 0 { + assert_eq!(prev, addr); + } + prev = addr; + } +} + +fn const_addr() -> usize { + "test".as_bytes().as_ptr().addr() +} diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs index 8c6eeab2219..8e46bd7ad48 100644 --- a/src/tools/miri/tests/pass/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics.rs @@ -33,6 +33,21 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); + let mut saw_true = false; + let mut saw_false = false; + + for _ in 0..50 { + if unsafe { intrinsics::is_val_statically_known(0) } { + saw_true = true; + } else { + saw_false = true; + } + } + assert!( + saw_true && saw_false, + "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" + ); + intrinsics::forget(Bomb); let _v = intrinsics::discriminant_value(&Some(())); |
