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 8b8e8ff58e907..417ab78fd5481 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{self, Abi}; -use super::{CompileTimeEvalContext, CompileTimeInterpreter}; +use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter}; use crate::errors; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ @@ -93,7 +93,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, root_span: Span, param_env: ty::ParamEnv<'tcx>, - can_access_statics: bool, + can_access_statics: CanAccessStatics, ) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( @@ -207,7 +207,7 @@ pub(crate) fn turn_into_const_value<'tcx>( tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, - /*can_access_statics:*/ is_static, + CanAccessStatics::from(is_static), ); let mplace = ecx.raw_const_to_mplace(constant).expect( @@ -309,7 +309,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // Statics (and promoteds inside statics) may access other statics, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. CompileTimeInterpreter::new( - /*can_access_statics:*/ is_static, + CanAccessStatics::from(is_static), if tcx.sess.opts.unstable_opts.extra_const_ub_checks { CheckAlignment::Error } else { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7391f5670400a..f9f645af41f19 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -57,7 +57,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// * Interning makes everything outside of statics immutable. /// * Pointers to allocations inside of statics can never leak outside, to a non-static global. /// This boolean here controls the second part. - pub(super) can_access_statics: bool, + pub(super) can_access_statics: CanAccessStatics, /// Whether to check alignment during evaluation. pub(super) check_alignment: CheckAlignment, @@ -83,8 +83,23 @@ impl CheckAlignment { } } +#[derive(Copy, Clone, PartialEq)] +pub(crate) enum CanAccessStatics { + No, + Yes, +} + +impl From for CanAccessStatics { + fn from(value: bool) -> Self { + if value { Self::Yes } else { Self::No } + } +} + impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self { + pub(crate) fn new( + can_access_statics: CanAccessStatics, + check_alignment: CheckAlignment, + ) -> Self { CompileTimeInterpreter { num_evaluated_steps: 0, stack: Vec::new(), @@ -699,7 +714,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } else { // Read access. These are usually allowed, with some exceptions. - if machine.can_access_statics { + if machine.can_access_statics == CanAccessStatics::Yes { // Machine configuration allows us read from anything (e.g., `static` initializer). Ok(()) } else if static_def_id.is_some() { diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6e462d3a1e983..b9ab0a4b7c8f4 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -26,7 +26,7 @@ pub(crate) fn const_caller_location( (file, line, col): (Symbol, u32, u32), ) -> ConstValue<'_> { trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No); let loc_place = ecx.alloc_caller_location(file, line, col); if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { @@ -55,10 +55,12 @@ pub(crate) fn eval_to_valtree<'tcx>( // FIXME Need to provide a span to `eval_to_valtree` let ecx = mk_eval_cx( - tcx, DUMMY_SP, param_env, + tcx, + DUMMY_SP, + param_env, // It is absolutely crucial for soundness that // we do not read from static items or other mutable memory. - false, + CanAccessStatics::No, ); let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); debug!(?place); @@ -91,7 +93,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>( val: mir::ConstantKind<'tcx>, ) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> { trace!("destructure_mir_constant: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No); let op = ecx.eval_mir_constant(&val, None, None)?; // We go to `usize` as we cannot allocate anything bigger anyway. diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index b10f2e9f862db..e574df27694f9 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,6 +1,7 @@ use super::eval_queries::{mk_eval_cx, op_to_const}; use super::machine::CompileTimeEvalContext; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; +use crate::const_eval::CanAccessStatics; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy, Scalar, @@ -263,7 +264,11 @@ pub fn valtree_to_const_value<'tcx>( // FIXME Does this need an example? let (param_env, ty) = param_env_ty.into_parts(); - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let mut ecx: crate::interpret::InterpCx< + '_, + '_, + crate::const_eval::CompileTimeInterpreter<'_, '_>, + > = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No); match ty.kind() { ty::FnDef(..) => { diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 29063261adab6..f56798d4c323c 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; -use crate::const_eval::{CheckAlignment, CompileTimeInterpreter}; +use crate::const_eval::{CanAccessStatics, CheckAlignment, CompileTimeInterpreter}; use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// Determines if this type permits "raw" initialization by just transmuting some memory into an @@ -44,8 +44,7 @@ fn might_permit_raw_init_strict<'tcx>( tcx: TyCtxt<'tcx>, kind: ValidityRequirement, ) -> Result> { - let machine = - CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error); + let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index a80379e85c193..7ce4599c4241f 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -5,7 +5,9 @@ //! parent directory, and otherwise documentation can be found throughout the `build` //! directory in each respective module. -use std::env; +use std::fs::OpenOptions; +use std::io::Write; +use std::{env, fs, process}; #[cfg(all(any(unix, windows), not(target_os = "solaris")))] use bootstrap::t; @@ -20,22 +22,32 @@ fn main() { #[cfg(all(any(unix, windows), not(target_os = "solaris")))] let _build_lock_guard; #[cfg(all(any(unix, windows), not(target_os = "solaris")))] + // Display PID of process holding the lock + // PID will be stored in a lock file { let path = config.out.join("lock"); - build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path))); + let pid = match fs::read_to_string(&path) { + Ok(contents) => contents, + Err(_) => String::new(), + }; + + build_lock = + fd_lock::RwLock::new(t!(OpenOptions::new().write(true).create(true).open(&path))); _build_lock_guard = match build_lock.try_write() { - Ok(lock) => lock, + Ok(mut lock) => { + t!(lock.write(&process::id().to_string().as_ref())); + lock + } err => { drop(err); - if let Some(pid) = get_lock_owner(&path) { - println!("warning: build directory locked by process {pid}, waiting for lock"); - } else { - println!("warning: build directory locked, waiting for lock"); - } - t!(build_lock.write()) + println!("warning: build directory locked by process {pid}, waiting for lock"); + let mut lock = t!(build_lock.write()); + t!(lock.write(&process::id().to_string().as_ref())); + lock } }; } + #[cfg(any(not(any(unix, windows)), target_os = "solaris"))] println!("warning: file locking not supported for target, not locking build directory"); @@ -108,30 +120,3 @@ fn check_version(config: &Config) -> Option { Some(msg) } - -/// Get the PID of the process which took the write lock by -/// parsing `/proc/locks`. -#[cfg(target_os = "linux")] -fn get_lock_owner(f: &std::path::Path) -> Option { - use std::fs::File; - use std::io::{BufRead, BufReader}; - use std::os::unix::fs::MetadataExt; - - let lock_inode = std::fs::metadata(f).ok()?.ino(); - let lockfile = File::open("/proc/locks").ok()?; - BufReader::new(lockfile).lines().find_map(|line| { - // pid--vvvvvv vvvvvvv--- inode - // 21: FLOCK ADVISORY WRITE 359238 08:02:3719774 0 EOF - let line = line.ok()?; - let parts = line.split_whitespace().collect::>(); - let (pid, inode) = (parts[4].parse::().ok()?, &parts[5]); - let inode = inode.rsplit_once(':')?.1.parse::().ok()?; - if inode == lock_inode { Some(pid) } else { None } - }) -} - -#[cfg(not(any(target_os = "linux", target_os = "solaris")))] -fn get_lock_owner(_: &std::path::Path) -> Option { - // FIXME: Implement on other OS's - None -} diff --git a/tests/ui/const-generics/generic_const_exprs/issue-96699.rs b/tests/ui/const-generics/generic_const_exprs/issue-96699.rs new file mode 100644 index 0000000000000..83f329d2a2dff --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/issue-96699.rs @@ -0,0 +1,87 @@ +// check-pass + +#![allow(dead_code, incomplete_features)] +#![feature(generic_const_exprs)] + +const fn min(a: usize, b: usize) -> usize { + if a < b { + a + } else { + b + } +} + +trait Trait1 +where + Self: Sized, +{ + fn crash_here() + where + Inner1: Default, + { + Inner1::default(); + } +} + +struct Struct1(T); +impl Trait1 for Struct1 {} + +trait Trait2 +where + Self: Sized, +{ + type Assoc: Trait1; + + fn call_crash() + where + Inner2: Default, + { + // if Inner2 implements Default, we can call crash_here. + Self::Assoc::crash_here(); + } +} + +struct Struct2 {} +/* +where + [(); min(SIZE1, SIZE2)]:, +{ + elem: [i32; min(SIZE1, SIZE2)], +} +*/ + +impl Trait2<[i32; min(SIZE1, SIZE2)]> + for Struct2 +{ + type Assoc = Struct1<[i32; min(SIZE1, SIZE2)]>; + // dose Struct1<[i32; min(SIZE1, SIZE2)]> implement Default? +} + +fn main() { + pattern2(); + + print_fully_name( as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here); + // as compiler_bug2::Trait1<[i32; 1]>>::crash_here +} + +fn pattern1() { + // no crash + as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here(); + as Trait2<[i32; min(1, 2)]>>::call_crash(); +} + +fn pattern2() { + // crash + as Trait2<[i32; min(1, 2)]>>::call_crash(); + + // undefined reference to `compiler_bug2::Trait1::crash_here' +} + +fn pattern3() { + // no crash + as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here(); +} + +fn print_fully_name(_: T) { + let _ = std::any::type_name::(); +} diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs index a776e5089075c..a9d678c1e6aff 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs @@ -1,4 +1,4 @@ -// compile-flags -Wrust-2021-incompatible-closure-captures +#![warn(rust_2021_incompatible_closure_captures)] fn main() {} @@ -9,7 +9,7 @@ impl Numberer { //~^ ERROR `async fn` is not permitted in Rust 2015 interval: Duration, //~^ ERROR cannot find type `Duration` in this scope - ) -> Numberer { + ) -> Numberer { //~WARN: changes to closure capture in Rust 2021 Numberer {} } } diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 60433e1c28467..71e9e7602e8e7 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -18,7 +18,32 @@ help: consider importing this struct LL + use std::time::Duration; | -error: aborting due to 2 previous errors +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19 + | +LL | interval: Duration, + | -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect +LL | +LL | ) -> Numberer { + | _________________-_^ + | | | + | | in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure +LL | | Numberer {} +LL | | } + | |_____^ + | + = note: for more information, see +note: the lint level is defined here + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9 + | +LL | #![warn(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a dummy let to cause `interval` to be fully captured + | +LL | ) -> Numberer { let _ = &interval; + | ++++++++++++++++++ + +error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0412, E0670. For more information about an error, try `rustc --explain E0412`.