Skip to content

Commit 0d03812

Browse files
committed
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
2 parents 3c5d71a + a3c147b commit 0d03812

File tree

9 files changed

+172
-54
lines changed

9 files changed

+172
-54
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
1414
use rustc_span::source_map::Span;
1515
use rustc_target::abi::{self, Abi};
1616

17-
use super::{CompileTimeEvalContext, CompileTimeInterpreter};
17+
use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
1818
use crate::errors;
1919
use crate::interpret::eval_nullary_intrinsic;
2020
use crate::interpret::{
@@ -93,7 +93,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
9393
tcx: TyCtxt<'tcx>,
9494
root_span: Span,
9595
param_env: ty::ParamEnv<'tcx>,
96-
can_access_statics: bool,
96+
can_access_statics: CanAccessStatics,
9797
) -> CompileTimeEvalContext<'mir, 'tcx> {
9898
debug!("mk_eval_cx: {:?}", param_env);
9999
InterpCx::new(
@@ -207,7 +207,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
207207
tcx,
208208
tcx.def_span(key.value.instance.def_id()),
209209
key.param_env,
210-
/*can_access_statics:*/ is_static,
210+
CanAccessStatics::from(is_static),
211211
);
212212

213213
let mplace = ecx.raw_const_to_mplace(constant).expect(
@@ -309,7 +309,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
309309
// Statics (and promoteds inside statics) may access other statics, because unlike consts
310310
// they do not have to behave "as if" they were evaluated at runtime.
311311
CompileTimeInterpreter::new(
312-
/*can_access_statics:*/ is_static,
312+
CanAccessStatics::from(is_static),
313313
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
314314
CheckAlignment::Error
315315
} else {

compiler/rustc_const_eval/src/const_eval/machine.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
5757
/// * Interning makes everything outside of statics immutable.
5858
/// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
5959
/// This boolean here controls the second part.
60-
pub(super) can_access_statics: bool,
60+
pub(super) can_access_statics: CanAccessStatics,
6161

6262
/// Whether to check alignment during evaluation.
6363
pub(super) check_alignment: CheckAlignment,
@@ -83,8 +83,23 @@ impl CheckAlignment {
8383
}
8484
}
8585

86+
#[derive(Copy, Clone, PartialEq)]
87+
pub(crate) enum CanAccessStatics {
88+
No,
89+
Yes,
90+
}
91+
92+
impl From<bool> for CanAccessStatics {
93+
fn from(value: bool) -> Self {
94+
if value { Self::Yes } else { Self::No }
95+
}
96+
}
97+
8698
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
87-
pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self {
99+
pub(crate) fn new(
100+
can_access_statics: CanAccessStatics,
101+
check_alignment: CheckAlignment,
102+
) -> Self {
88103
CompileTimeInterpreter {
89104
num_evaluated_steps: 0,
90105
stack: Vec::new(),
@@ -699,7 +714,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
699714
}
700715
} else {
701716
// Read access. These are usually allowed, with some exceptions.
702-
if machine.can_access_statics {
717+
if machine.can_access_statics == CanAccessStatics::Yes {
703718
// Machine configuration allows us read from anything (e.g., `static` initializer).
704719
Ok(())
705720
} else if static_def_id.is_some() {

compiler/rustc_const_eval/src/const_eval/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub(crate) fn const_caller_location(
2626
(file, line, col): (Symbol, u32, u32),
2727
) -> ConstValue<'_> {
2828
trace!("const_caller_location: {}:{}:{}", file, line, col);
29-
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
29+
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No);
3030

3131
let loc_place = ecx.alloc_caller_location(file, line, col);
3232
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
@@ -55,10 +55,12 @@ pub(crate) fn eval_to_valtree<'tcx>(
5555

5656
// FIXME Need to provide a span to `eval_to_valtree`
5757
let ecx = mk_eval_cx(
58-
tcx, DUMMY_SP, param_env,
58+
tcx,
59+
DUMMY_SP,
60+
param_env,
5961
// It is absolutely crucial for soundness that
6062
// we do not read from static items or other mutable memory.
61-
false,
63+
CanAccessStatics::No,
6264
);
6365
let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
6466
debug!(?place);
@@ -91,7 +93,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
9193
val: mir::ConstantKind<'tcx>,
9294
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
9395
trace!("destructure_mir_constant: {:?}", val);
94-
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
96+
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
9597
let op = ecx.eval_mir_constant(&val, None, None)?;
9698

9799
// We go to `usize` as we cannot allocate anything bigger anyway.

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::eval_queries::{mk_eval_cx, op_to_const};
22
use super::machine::CompileTimeEvalContext;
33
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
4+
use crate::const_eval::CanAccessStatics;
45
use crate::interpret::{
56
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
67
MemoryKind, PlaceTy, Scalar,
@@ -263,7 +264,11 @@ pub fn valtree_to_const_value<'tcx>(
263264
// FIXME Does this need an example?
264265

265266
let (param_env, ty) = param_env_ty.into_parts();
266-
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
267+
let mut ecx: crate::interpret::InterpCx<
268+
'_,
269+
'_,
270+
crate::const_eval::CompileTimeInterpreter<'_, '_>,
271+
> = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
267272

268273
match ty.kind() {
269274
ty::FnDef(..) => {

compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
22
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
33
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
44

5-
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
5+
use crate::const_eval::{CanAccessStatics, CheckAlignment, CompileTimeInterpreter};
66
use crate::interpret::{InterpCx, MemoryKind, OpTy};
77

88
/// 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>(
4444
tcx: TyCtxt<'tcx>,
4545
kind: ValidityRequirement,
4646
) -> Result<bool, LayoutError<'tcx>> {
47-
let machine =
48-
CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
47+
let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
4948

5049
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
5150

src/bootstrap/bin/main.rs

+21-36
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
//! parent directory, and otherwise documentation can be found throughout the `build`
66
//! directory in each respective module.
77
8-
use std::env;
8+
use std::fs::OpenOptions;
9+
use std::io::Write;
10+
use std::{env, fs, process};
911

1012
#[cfg(all(any(unix, windows), not(target_os = "solaris")))]
1113
use bootstrap::t;
@@ -20,22 +22,32 @@ fn main() {
2022
#[cfg(all(any(unix, windows), not(target_os = "solaris")))]
2123
let _build_lock_guard;
2224
#[cfg(all(any(unix, windows), not(target_os = "solaris")))]
25+
// Display PID of process holding the lock
26+
// PID will be stored in a lock file
2327
{
2428
let path = config.out.join("lock");
25-
build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
29+
let pid = match fs::read_to_string(&path) {
30+
Ok(contents) => contents,
31+
Err(_) => String::new(),
32+
};
33+
34+
build_lock =
35+
fd_lock::RwLock::new(t!(OpenOptions::new().write(true).create(true).open(&path)));
2636
_build_lock_guard = match build_lock.try_write() {
27-
Ok(lock) => lock,
37+
Ok(mut lock) => {
38+
t!(lock.write(&process::id().to_string().as_ref()));
39+
lock
40+
}
2841
err => {
2942
drop(err);
30-
if let Some(pid) = get_lock_owner(&path) {
31-
println!("warning: build directory locked by process {pid}, waiting for lock");
32-
} else {
33-
println!("warning: build directory locked, waiting for lock");
34-
}
35-
t!(build_lock.write())
43+
println!("warning: build directory locked by process {pid}, waiting for lock");
44+
let mut lock = t!(build_lock.write());
45+
t!(lock.write(&process::id().to_string().as_ref()));
46+
lock
3647
}
3748
};
3849
}
50+
3951
#[cfg(any(not(any(unix, windows)), target_os = "solaris"))]
4052
println!("warning: file locking not supported for target, not locking build directory");
4153

@@ -108,30 +120,3 @@ fn check_version(config: &Config) -> Option<String> {
108120

109121
Some(msg)
110122
}
111-
112-
/// Get the PID of the process which took the write lock by
113-
/// parsing `/proc/locks`.
114-
#[cfg(target_os = "linux")]
115-
fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
116-
use std::fs::File;
117-
use std::io::{BufRead, BufReader};
118-
use std::os::unix::fs::MetadataExt;
119-
120-
let lock_inode = std::fs::metadata(f).ok()?.ino();
121-
let lockfile = File::open("/proc/locks").ok()?;
122-
BufReader::new(lockfile).lines().find_map(|line| {
123-
// pid--vvvvvv vvvvvvv--- inode
124-
// 21: FLOCK ADVISORY WRITE 359238 08:02:3719774 0 EOF
125-
let line = line.ok()?;
126-
let parts = line.split_whitespace().collect::<Vec<_>>();
127-
let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
128-
let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
129-
if inode == lock_inode { Some(pid) } else { None }
130-
})
131-
}
132-
133-
#[cfg(not(any(target_os = "linux", target_os = "solaris")))]
134-
fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
135-
// FIXME: Implement on other OS's
136-
None
137-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// check-pass
2+
3+
#![allow(dead_code, incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
const fn min(a: usize, b: usize) -> usize {
7+
if a < b {
8+
a
9+
} else {
10+
b
11+
}
12+
}
13+
14+
trait Trait1<Inner1>
15+
where
16+
Self: Sized,
17+
{
18+
fn crash_here()
19+
where
20+
Inner1: Default,
21+
{
22+
Inner1::default();
23+
}
24+
}
25+
26+
struct Struct1<T>(T);
27+
impl<T> Trait1<T> for Struct1<T> {}
28+
29+
trait Trait2<Inner2>
30+
where
31+
Self: Sized,
32+
{
33+
type Assoc: Trait1<Inner2>;
34+
35+
fn call_crash()
36+
where
37+
Inner2: Default,
38+
{
39+
// if Inner2 implements Default, we can call crash_here.
40+
Self::Assoc::crash_here();
41+
}
42+
}
43+
44+
struct Struct2<const SIZE1: usize, const SIZE2: usize> {}
45+
/*
46+
where
47+
[(); min(SIZE1, SIZE2)]:,
48+
{
49+
elem: [i32; min(SIZE1, SIZE2)],
50+
}
51+
*/
52+
53+
impl<const SIZE1: usize, const SIZE2: usize> Trait2<[i32; min(SIZE1, SIZE2)]>
54+
for Struct2<SIZE1, SIZE2>
55+
{
56+
type Assoc = Struct1<[i32; min(SIZE1, SIZE2)]>;
57+
// dose Struct1<[i32; min(SIZE1, SIZE2)]> implement Default?
58+
}
59+
60+
fn main() {
61+
pattern2();
62+
63+
print_fully_name(<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here);
64+
// <compiler_bug2::Struct1<[i32; 1]> as compiler_bug2::Trait1<[i32; 1]>>::crash_here
65+
}
66+
67+
fn pattern1() {
68+
// no crash
69+
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
70+
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
71+
}
72+
73+
fn pattern2() {
74+
// crash
75+
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
76+
77+
// undefined reference to `compiler_bug2::Trait1::crash_here'
78+
}
79+
80+
fn pattern3() {
81+
// no crash
82+
<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
83+
}
84+
85+
fn print_fully_name<T>(_: T) {
86+
let _ = std::any::type_name::<T>();
87+
}

tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// compile-flags -Wrust-2021-incompatible-closure-captures
1+
#![warn(rust_2021_incompatible_closure_captures)]
22

33
fn main() {}
44

@@ -9,7 +9,7 @@ impl Numberer {
99
//~^ ERROR `async fn` is not permitted in Rust 2015
1010
interval: Duration,
1111
//~^ ERROR cannot find type `Duration` in this scope
12-
) -> Numberer {
12+
) -> Numberer { //~WARN: changes to closure capture in Rust 2021
1313
Numberer {}
1414
}
1515
}

tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr

+26-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,32 @@ help: consider importing this struct
1818
LL + use std::time::Duration;
1919
|
2020

21-
error: aborting due to 2 previous errors
21+
warning: changes to closure capture in Rust 2021 will affect drop order
22+
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19
23+
|
24+
LL | interval: Duration,
25+
| -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect
26+
LL |
27+
LL | ) -> Numberer {
28+
| _________________-_^
29+
| | |
30+
| | in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure
31+
LL | | Numberer {}
32+
LL | | }
33+
| |_____^
34+
|
35+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
36+
note: the lint level is defined here
37+
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9
38+
|
39+
LL | #![warn(rust_2021_incompatible_closure_captures)]
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
help: add a dummy let to cause `interval` to be fully captured
42+
|
43+
LL | ) -> Numberer { let _ = &interval;
44+
| ++++++++++++++++++
45+
46+
error: aborting due to 2 previous errors; 1 warning emitted
2247

2348
Some errors have detailed explanations: E0412, E0670.
2449
For more information about an error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)