Skip to content

Commit cc633f4

Browse files
authored
Rollup merge of rust-lang#65485 - ecstatic-morse:const-validation-mismatch-ugliness, r=eddyb
Suppress ICE when validators disagree on `LiveDrop`s in presence of `&mut` Resolves rust-lang#65394. This hack disables the validator mismatch ICE in cases where a `MutBorrow` error has been emitted by both validators, but they don't agree on the number of `LiveDrop` errors. The new validator is more conservative about whether a value is moved from in the presence of mutable borrows. For example, the new validator will emit a `LiveDrop` error on the following code. ```rust const _: Vec<i32> = { let mut x = Vec::new(); let px = &mut x as *mut _; let y = x; unsafe { ptr::write(px, Vec::new()); } y }; ``` This code is not UB AFAIK (it passes MIRI at least). The current validator does not emit a `LiveDrop` error for `x` upon exit from the initializer. `x` is not actually dropped, so I think this is correct? A proper fix for this would require a new `MaybeInitializedLocals` dataflow analysis or maybe a relaxation of the existing `IndirectlyMutableLocals` one. r? @RalfJung
2 parents 94102ef + af691de commit cc633f4

File tree

4 files changed

+83
-17
lines changed

4 files changed

+83
-17
lines changed

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
1414
#![feature(core_intrinsics)]
1515
#![feature(const_fn)]
1616
#![feature(decl_macro)]
17+
#![feature(drain_filter)]
1718
#![feature(exhaustive_patterns)]
1819
#![feature(never_type)]
1920
#![feature(specialization)]

src/librustc_mir/transform/qualify_consts.rs

+58-17
Original file line numberDiff line numberDiff line change
@@ -1024,23 +1024,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
10241024
new_errors.dedup();
10251025

10261026
if self.errors != new_errors {
1027-
error!("old validator: {:?}", self.errors);
1028-
error!("new validator: {:?}", new_errors);
1029-
1030-
// ICE on nightly if the validators do not emit exactly the same errors.
1031-
// Users can supress this panic with an unstable compiler flag (hopefully after
1032-
// filing an issue).
1033-
let opts = &self.tcx.sess.opts;
1034-
let trigger_ice = opts.unstable_features.is_nightly_build()
1035-
&& !opts.debugging_opts.suppress_const_validation_back_compat_ice;
1036-
1037-
if trigger_ice {
1038-
span_bug!(
1039-
body.span,
1040-
"{}",
1041-
VALIDATOR_MISMATCH_ERR,
1042-
);
1043-
}
1027+
validator_mismatch(
1028+
self.tcx,
1029+
body,
1030+
std::mem::replace(&mut self.errors, vec![]),
1031+
new_errors,
1032+
);
10441033
}
10451034
}
10461035

@@ -1870,6 +1859,58 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<FxHashSet<usize
18701859
Some(ret)
18711860
}
18721861

1862+
fn validator_mismatch(
1863+
tcx: TyCtxt<'tcx>,
1864+
body: &Body<'tcx>,
1865+
mut old_errors: Vec<(Span, String)>,
1866+
mut new_errors: Vec<(Span, String)>,
1867+
) {
1868+
error!("old validator: {:?}", old_errors);
1869+
error!("new validator: {:?}", new_errors);
1870+
1871+
// ICE on nightly if the validators do not emit exactly the same errors.
1872+
// Users can supress this panic with an unstable compiler flag (hopefully after
1873+
// filing an issue).
1874+
let opts = &tcx.sess.opts;
1875+
let strict_validation_enabled = opts.unstable_features.is_nightly_build()
1876+
&& !opts.debugging_opts.suppress_const_validation_back_compat_ice;
1877+
1878+
if !strict_validation_enabled {
1879+
return;
1880+
}
1881+
1882+
// If this difference would cause a regression from the old to the new or vice versa, trigger
1883+
// the ICE.
1884+
if old_errors.is_empty() || new_errors.is_empty() {
1885+
span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
1886+
}
1887+
1888+
// HACK: Borrows that would allow mutation are forbidden in const contexts, but they cause the
1889+
// new validator to be more conservative about when a dropped local has been moved out of.
1890+
//
1891+
// Supress the mismatch ICE in cases where the validators disagree only on the number of
1892+
// `LiveDrop` errors and both observe the same sequence of `MutBorrow`s.
1893+
1894+
let is_live_drop = |(_, s): &mut (_, String)| s.starts_with("LiveDrop");
1895+
let is_mut_borrow = |(_, s): &&(_, String)| s.starts_with("MutBorrow");
1896+
1897+
let old_live_drops: Vec<_> = old_errors.drain_filter(is_live_drop).collect();
1898+
let new_live_drops: Vec<_> = new_errors.drain_filter(is_live_drop).collect();
1899+
1900+
let only_live_drops_differ = old_live_drops != new_live_drops && old_errors == new_errors;
1901+
1902+
let old_mut_borrows = old_errors.iter().filter(is_mut_borrow);
1903+
let new_mut_borrows = new_errors.iter().filter(is_mut_borrow);
1904+
1905+
let at_least_one_mut_borrow = old_mut_borrows.clone().next().is_some();
1906+
1907+
if only_live_drops_differ && at_least_one_mut_borrow && old_mut_borrows.eq(new_mut_borrows) {
1908+
return;
1909+
}
1910+
1911+
span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
1912+
}
1913+
18731914
const VALIDATOR_MISMATCH_ERR: &str =
18741915
r"Disagreement between legacy and dataflow-based const validators.
18751916
After filing an issue, use `-Zsuppress-const-validation-back-compat-ice` to compile your code.";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Test for absence of validation mismatch ICE in #65394
2+
3+
#![feature(rustc_attrs)]
4+
5+
#[rustc_mir(borrowck_graphviz_postflow="hello.dot")]
6+
const _: Vec<i32> = {
7+
let mut x = Vec::<i32>::new();
8+
let r = &mut x; //~ ERROR references in constants may only refer to immutable values
9+
let y = x;
10+
y
11+
};
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0017]: references in constants may only refer to immutable values
2+
--> $DIR/issue-65394.rs:8:13
3+
|
4+
LL | let r = &mut x;
5+
| ^^^^^^ constants require immutable values
6+
7+
[ERROR rustc_mir::transform::qualify_consts] old validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")]
8+
[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:7:9: 7:14, "LiveDrop")]
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0017`.

0 commit comments

Comments
 (0)