Skip to content

Commit b139669

Browse files
committed
Auto merge of #56123 - oli-obk:import_miri_from_future, r=eddyb
Add a forever unstable opt-out of const qualification checks r? @eddyb cc @RalfJung @Centril basically a forever unstable way to screw with const things in horribly unsafe, unsound and incoherent ways. Note that this does *not* affect miri except by maybe violating assumptions that miri makes. But there's no change in how miri evaluates things.
2 parents 2596bc1 + d0129a6 commit b139669

8 files changed

+155
-2
lines changed

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
13051305
"print some statistics about AST and HIR"),
13061306
always_encode_mir: bool = (false, parse_bool, [TRACKED],
13071307
"encode MIR of all functions into the crate metadata"),
1308+
unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1309+
"take the breaks off const evaluation. NOTE: this is unsound"),
13081310
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
13091311
"pass `-install_name @rpath/...` to the macOS linker"),
13101312
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],

src/librustc_mir/transform/qualify_consts.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
108108
promotion_candidates: Vec<Candidate>
109109
}
110110

111+
macro_rules! unleash_miri {
112+
($this:expr) => {{
113+
if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
114+
$this.tcx.sess.span_warn($this.span, "skipping const checks");
115+
return;
116+
}
117+
}}
118+
}
119+
111120
impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
112121
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
113122
def_id: DefId,
@@ -147,6 +156,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
147156
// categories, but enabling full miri would make that
148157
// slightly pointless (even with feature-gating).
149158
fn not_const(&mut self) {
159+
unleash_miri!(self);
150160
self.add(Qualif::NOT_CONST);
151161
if self.mode != Mode::Fn {
152162
let mut err = struct_span_err!(
@@ -419,6 +429,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
419429
}
420430
return;
421431
}
432+
unleash_miri!(self);
422433
self.add(Qualif::NOT_CONST);
423434

424435
if self.mode != Mode::Fn {
@@ -618,6 +629,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
618629
}
619630

620631
if forbidden_mut {
632+
unleash_miri!(self);
621633
self.add(Qualif::NOT_CONST);
622634
if self.mode != Mode::Fn {
623635
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
@@ -660,6 +672,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
660672

661673
debug!("visit_rvalue: forbidden_mut={:?}", forbidden_mut);
662674
if forbidden_mut {
675+
unleash_miri!(self);
663676
self.add(Qualif::NOT_CONST);
664677
} else {
665678
// We might have a candidate for promotion.
@@ -700,6 +713,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
700713
match (cast_in, cast_out) {
701714
(CastTy::Ptr(_), CastTy::Int(_)) |
702715
(CastTy::FnPtr, CastTy::Int(_)) => {
716+
unleash_miri!(self);
703717
if let Mode::Fn = self.mode {
704718
// in normal functions, mark such casts as not promotable
705719
self.add(Qualif::NOT_CONST);
@@ -727,6 +741,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
727741
op == BinOp::Ge || op == BinOp::Gt ||
728742
op == BinOp::Offset);
729743

744+
unleash_miri!(self);
730745
if let Mode::Fn = self.mode {
731746
// raw pointer operations are not allowed inside promoteds
732747
self.add(Qualif::NOT_CONST);
@@ -745,6 +760,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
745760
}
746761

747762
Rvalue::NullaryOp(NullOp::Box, _) => {
763+
unleash_miri!(self);
748764
self.add(Qualif::NOT_CONST);
749765
if self.mode != Mode::Fn {
750766
let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
@@ -861,7 +877,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
861877
} else {
862878
// stable const fns or unstable const fns with their feature gate
863879
// active
864-
if self.tcx.is_const_fn(def_id) {
880+
let unleash_miri = self
881+
.tcx
882+
.sess
883+
.opts
884+
.debugging_opts
885+
.unleash_the_miri_inside_of_you;
886+
if self.tcx.is_const_fn(def_id) || unleash_miri {
865887
is_const_fn = true;
866888
} else if self.is_const_panic_fn(def_id) {
867889
// Check the const_panic feature gate.
@@ -1030,6 +1052,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
10301052

10311053
// Deny *any* live drops anywhere other than functions.
10321054
if self.mode != Mode::Fn {
1055+
unleash_miri!(self);
10331056
// HACK(eddyb): emulate a bit of dataflow analysis,
10341057
// conservatively, that drop elaboration will do.
10351058
let needs_drop = if let Place::Local(local) = *place {
@@ -1175,7 +1198,9 @@ impl MirPass for QualifyAndPromoteConstants {
11751198
let (temps, candidates) = {
11761199
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
11771200
if mode == Mode::ConstFn {
1178-
if tcx.is_min_const_fn(def_id) {
1201+
if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
1202+
qualifier.qualify_const();
1203+
} else if tcx.is_min_const_fn(def_id) {
11791204
// enforce `min_const_fn` for stable const fns
11801205
use super::qualify_min_const_fn::is_min_const_fn;
11811206
if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// compile-flags: -Zunleash-the-miri-inside-of-you
2+
#![allow(const_err)]
3+
4+
// a test demonstrating why we do need to run static const qualification on associated constants
5+
// instead of just checking the final constant
6+
7+
trait Foo<T> {
8+
const X: T;
9+
}
10+
11+
trait Bar<T, U: Foo<T>> {
12+
const F: u32 = (U::X, 42).1; //~ WARN skipping const checks
13+
}
14+
15+
impl Foo<u32> for () {
16+
const X: u32 = 42;
17+
}
18+
impl Foo<Vec<u32>> for String {
19+
const X: Vec<u32> = Vec::new();
20+
}
21+
22+
impl Bar<u32, ()> for () {}
23+
impl Bar<Vec<u32>, String> for String {}
24+
25+
fn main() {
26+
// this is fine, but would have been forbidden by the static checks on `F`
27+
let x = <() as Bar<u32, ()>>::F;
28+
// this test only causes errors due to the line below, so post-monomorphization
29+
let y = <String as Bar<Vec<u32>, String>>::F; //~ ERROR erroneous constant
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning: skipping const checks
2+
--> $DIR/assoc_const.rs:12:31
3+
|
4+
LL | const F: u32 = (U::X, 42).1; //~ WARN skipping const checks
5+
| ^
6+
7+
error[E0080]: erroneous constant used
8+
--> $DIR/assoc_const.rs:29:13
9+
|
10+
LL | let y = <String as Bar<Vec<u32>, String>>::F; //~ ERROR erroneous constant
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![allow(const_err)]
2+
3+
// a test demonstrating that const qualification cannot prevent monomorphization time errors
4+
5+
trait Foo {
6+
const X: u32;
7+
}
8+
9+
trait Bar<U: Foo> {
10+
const F: u32 = 100 / U::X;
11+
}
12+
13+
impl Foo for () {
14+
const X: u32 = 42;
15+
}
16+
17+
impl Foo for String {
18+
const X: u32 = 0;
19+
}
20+
21+
impl Bar<()> for () {}
22+
impl Bar<String> for String {}
23+
24+
fn main() {
25+
let x = <() as Bar<()>>::F;
26+
// this test only causes errors due to the line below, so post-monomorphization
27+
let y = <String as Bar<String>>::F; //~ ERROR erroneous constant
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: erroneous constant used
2+
--> $DIR/assoc_const_2.rs:27:13
3+
|
4+
LL | let y = <String as Bar<String>>::F; //~ ERROR erroneous constant
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![allow(const_err)]
2+
3+
// a test demonstrating why we do need to run static const qualification on associated constants
4+
// instead of just checking the final constant
5+
6+
trait Foo<T> {
7+
const X: T;
8+
}
9+
10+
trait Bar<T, U: Foo<T>> {
11+
const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time
12+
}
13+
14+
impl Foo<u32> for () {
15+
const X: u32 = 42;
16+
}
17+
impl Foo<Vec<u32>> for String {
18+
const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
19+
}
20+
21+
impl Bar<u32, ()> for () {}
22+
impl Bar<Vec<u32>, String> for String {}
23+
24+
fn main() {
25+
let x = <() as Bar<u32, ()>>::F;
26+
let y = <String as Bar<Vec<u32>, String>>::F;
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0493]: destructors cannot be evaluated at compile-time
2+
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
3+
|
4+
LL | const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time
5+
| ^^^^^^^^^^ constants cannot evaluate destructors
6+
7+
error: `<std::vec::Vec<T>>::new` is not yet stable as a const fn
8+
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25
9+
|
10+
LL | const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
11+
| ^^^^^^^^^^
12+
|
13+
= help: add `#![feature(const_vec_new)]` to the crate attributes to enable
14+
15+
error: aborting due to 2 previous errors
16+
17+
For more information about this error, try `rustc --explain E0493`.

0 commit comments

Comments
 (0)