Auto merge of #113022 - GuillaumeGomez:rollup-vkpzsuw, r=GuillaumeGomez

Rollup of 4 pull requests

Successful merges:

 - #112918 (display PID of process holding lock)
 - #112990 (Add a regression test for #96699)
 - #113011 (Add enum for `can_access_statics` boolean)
 - #113018 (Fix test for #96258)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-06-25 08:51:49 +00:00
commit 0d03812e24
9 changed files with 172 additions and 54 deletions

View File

@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_target::abi::{self, Abi}; use rustc_target::abi::{self, Abi};
use super::{CompileTimeEvalContext, CompileTimeInterpreter}; use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
use crate::errors; use crate::errors;
use crate::interpret::eval_nullary_intrinsic; use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{ use crate::interpret::{
@ -93,7 +93,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
root_span: Span, root_span: Span,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
can_access_statics: bool, can_access_statics: CanAccessStatics,
) -> CompileTimeEvalContext<'mir, 'tcx> { ) -> CompileTimeEvalContext<'mir, 'tcx> {
debug!("mk_eval_cx: {:?}", param_env); debug!("mk_eval_cx: {:?}", param_env);
InterpCx::new( InterpCx::new(
@ -207,7 +207,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
tcx, tcx,
tcx.def_span(key.value.instance.def_id()), tcx.def_span(key.value.instance.def_id()),
key.param_env, key.param_env,
/*can_access_statics:*/ is_static, CanAccessStatics::from(is_static),
); );
let mplace = ecx.raw_const_to_mplace(constant).expect( 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 // 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. // they do not have to behave "as if" they were evaluated at runtime.
CompileTimeInterpreter::new( CompileTimeInterpreter::new(
/*can_access_statics:*/ is_static, CanAccessStatics::from(is_static),
if tcx.sess.opts.unstable_opts.extra_const_ub_checks { if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
CheckAlignment::Error CheckAlignment::Error
} else { } else {

View File

@ -57,7 +57,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// * Interning makes everything outside of statics immutable. /// * Interning makes everything outside of statics immutable.
/// * Pointers to allocations inside of statics can never leak outside, to a non-static global. /// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
/// This boolean here controls the second part. /// 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. /// Whether to check alignment during evaluation.
pub(super) check_alignment: CheckAlignment, pub(super) check_alignment: CheckAlignment,
@ -83,8 +83,23 @@ impl CheckAlignment {
} }
} }
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum CanAccessStatics {
No,
Yes,
}
impl From<bool> for CanAccessStatics {
fn from(value: bool) -> Self {
if value { Self::Yes } else { Self::No }
}
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { 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 { CompileTimeInterpreter {
num_evaluated_steps: 0, num_evaluated_steps: 0,
stack: Vec::new(), stack: Vec::new(),
@ -699,7 +714,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
} }
} else { } else {
// Read access. These are usually allowed, with some exceptions. // 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). // Machine configuration allows us read from anything (e.g., `static` initializer).
Ok(()) Ok(())
} else if static_def_id.is_some() { } else if static_def_id.is_some() {

View File

@ -26,7 +26,7 @@ pub(crate) fn const_caller_location(
(file, line, col): (Symbol, u32, u32), (file, line, col): (Symbol, u32, u32),
) -> ConstValue<'_> { ) -> ConstValue<'_> {
trace!("const_caller_location: {}:{}:{}", file, line, col); 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); let loc_place = ecx.alloc_caller_location(file, line, col);
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { 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` // FIXME Need to provide a span to `eval_to_valtree`
let ecx = mk_eval_cx( let ecx = mk_eval_cx(
tcx, DUMMY_SP, param_env, tcx,
DUMMY_SP,
param_env,
// It is absolutely crucial for soundness that // It is absolutely crucial for soundness that
// we do not read from static items or other mutable memory. // we do not read from static items or other mutable memory.
false, CanAccessStatics::No,
); );
let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
debug!(?place); debug!(?place);
@ -91,7 +93,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
val: mir::ConstantKind<'tcx>, val: mir::ConstantKind<'tcx>,
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> { ) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
trace!("destructure_mir_constant: {:?}", val); 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)?; let op = ecx.eval_mir_constant(&val, None, None)?;
// We go to `usize` as we cannot allocate anything bigger anyway. // We go to `usize` as we cannot allocate anything bigger anyway.

View File

@ -1,6 +1,7 @@
use super::eval_queries::{mk_eval_cx, op_to_const}; use super::eval_queries::{mk_eval_cx, op_to_const};
use super::machine::CompileTimeEvalContext; use super::machine::CompileTimeEvalContext;
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
use crate::const_eval::CanAccessStatics;
use crate::interpret::{ use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
MemoryKind, PlaceTy, Scalar, MemoryKind, PlaceTy, Scalar,
@ -263,7 +264,11 @@ pub fn valtree_to_const_value<'tcx>(
// FIXME Does this need an example? // FIXME Does this need an example?
let (param_env, ty) = param_env_ty.into_parts(); 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() { match ty.kind() {
ty::FnDef(..) => { ty::FnDef(..) => {

View File

@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; 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}; use crate::interpret::{InterpCx, MemoryKind, OpTy};
/// Determines if this type permits "raw" initialization by just transmuting some memory into an /// 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>, tcx: TyCtxt<'tcx>,
kind: ValidityRequirement, kind: ValidityRequirement,
) -> Result<bool, LayoutError<'tcx>> { ) -> Result<bool, LayoutError<'tcx>> {
let machine = let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);

View File

@ -5,7 +5,9 @@
//! parent directory, and otherwise documentation can be found throughout the `build` //! parent directory, and otherwise documentation can be found throughout the `build`
//! directory in each respective module. //! 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")))] #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
use bootstrap::t; use bootstrap::t;
@ -20,22 +22,32 @@ fn main() {
#[cfg(all(any(unix, windows), not(target_os = "solaris")))] #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
let _build_lock_guard; let _build_lock_guard;
#[cfg(all(any(unix, windows), not(target_os = "solaris")))] #[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"); 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() { _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 => { err => {
drop(err); drop(err);
if let Some(pid) = get_lock_owner(&path) {
println!("warning: build directory locked by process {pid}, waiting for lock"); println!("warning: build directory locked by process {pid}, waiting for lock");
} else { let mut lock = t!(build_lock.write());
println!("warning: build directory locked, waiting for lock"); t!(lock.write(&process::id().to_string().as_ref()));
} lock
t!(build_lock.write())
} }
}; };
} }
#[cfg(any(not(any(unix, windows)), target_os = "solaris"))] #[cfg(any(not(any(unix, windows)), target_os = "solaris"))]
println!("warning: file locking not supported for target, not locking build directory"); println!("warning: file locking not supported for target, not locking build directory");
@ -108,30 +120,3 @@ fn check_version(config: &Config) -> Option<String> {
Some(msg) 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<u64> {
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::<Vec<_>>();
let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
let inode = inode.rsplit_once(':')?.1.parse::<u64>().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<u64> {
// FIXME: Implement on other OS's
None
}

View File

@ -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<Inner1>
where
Self: Sized,
{
fn crash_here()
where
Inner1: Default,
{
Inner1::default();
}
}
struct Struct1<T>(T);
impl<T> Trait1<T> for Struct1<T> {}
trait Trait2<Inner2>
where
Self: Sized,
{
type Assoc: Trait1<Inner2>;
fn call_crash()
where
Inner2: Default,
{
// if Inner2 implements Default, we can call crash_here.
Self::Assoc::crash_here();
}
}
struct Struct2<const SIZE1: usize, const SIZE2: usize> {}
/*
where
[(); min(SIZE1, SIZE2)]:,
{
elem: [i32; min(SIZE1, SIZE2)],
}
*/
impl<const SIZE1: usize, const SIZE2: usize> Trait2<[i32; min(SIZE1, SIZE2)]>
for Struct2<SIZE1, SIZE2>
{
type Assoc = Struct1<[i32; min(SIZE1, SIZE2)]>;
// dose Struct1<[i32; min(SIZE1, SIZE2)]> implement Default?
}
fn main() {
pattern2();
print_fully_name(<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here);
// <compiler_bug2::Struct1<[i32; 1]> as compiler_bug2::Trait1<[i32; 1]>>::crash_here
}
fn pattern1() {
// no crash
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
}
fn pattern2() {
// crash
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
// undefined reference to `compiler_bug2::Trait1::crash_here'
}
fn pattern3() {
// no crash
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
}
fn print_fully_name<T>(_: T) {
let _ = std::any::type_name::<T>();
}

View File

@ -1,4 +1,4 @@
// compile-flags -Wrust-2021-incompatible-closure-captures #![warn(rust_2021_incompatible_closure_captures)]
fn main() {} fn main() {}
@ -9,7 +9,7 @@ impl Numberer {
//~^ ERROR `async fn` is not permitted in Rust 2015 //~^ ERROR `async fn` is not permitted in Rust 2015
interval: Duration, interval: Duration,
//~^ ERROR cannot find type `Duration` in this scope //~^ ERROR cannot find type `Duration` in this scope
) -> Numberer { ) -> Numberer { //~WARN: changes to closure capture in Rust 2021
Numberer {} Numberer {}
} }
} }

View File

@ -18,7 +18,32 @@ help: consider importing this struct
LL + use std::time::Duration; 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
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. Some errors have detailed explanations: E0412, E0670.
For more information about an error, try `rustc --explain E0412`. For more information about an error, try `rustc --explain E0412`.