Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a forever unstable opt-out of const qualification checks #56123

Merged
merged 1 commit into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"print some statistics about AST and HIR"),
always_encode_mir: bool = (false, parse_bool, [TRACKED],
"encode MIR of all functions into the crate metadata"),
unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
"take the breaks off const evaluation. NOTE: this is unsound"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
"pass `-install_name @rpath/...` to the macOS linker"),
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
Expand Down
29 changes: 27 additions & 2 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
promotion_candidates: Vec<Candidate>
}

macro_rules! unleash_miri {
($this:expr) => {{
if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
$this.tcx.sess.span_warn($this.span, "skipping const checks");
return;
}
}}
}

impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
Expand Down Expand Up @@ -147,6 +156,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
// categories, but enabling full miri would make that
// slightly pointless (even with feature-gating).
fn not_const(&mut self) {
unleash_miri!(self);
self.add(Qualif::NOT_CONST);
if self.mode != Mode::Fn {
let mut err = struct_span_err!(
Expand Down Expand Up @@ -419,6 +429,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}
return;
}
unleash_miri!(self);
self.add(Qualif::NOT_CONST);

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

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

debug!("visit_rvalue: forbidden_mut={:?}", forbidden_mut);
if forbidden_mut {
unleash_miri!(self);
self.add(Qualif::NOT_CONST);
} else {
// We might have a candidate for promotion.
Expand Down Expand Up @@ -700,6 +713,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
match (cast_in, cast_out) {
(CastTy::Ptr(_), CastTy::Int(_)) |
(CastTy::FnPtr, CastTy::Int(_)) => {
unleash_miri!(self);
if let Mode::Fn = self.mode {
// in normal functions, mark such casts as not promotable
self.add(Qualif::NOT_CONST);
Expand Down Expand Up @@ -727,6 +741,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
op == BinOp::Ge || op == BinOp::Gt ||
op == BinOp::Offset);

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

Rvalue::NullaryOp(NullOp::Box, _) => {
unleash_miri!(self);
self.add(Qualif::NOT_CONST);
if self.mode != Mode::Fn {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
Expand Down Expand Up @@ -861,7 +877,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
} else {
// stable const fns or unstable const fns with their feature gate
// active
if self.tcx.is_const_fn(def_id) {
let unleash_miri = self
.tcx
.sess
.opts
.debugging_opts
.unleash_the_miri_inside_of_you;
if self.tcx.is_const_fn(def_id) || unleash_miri {
is_const_fn = true;
} else if self.is_const_panic_fn(def_id) {
// Check the const_panic feature gate.
Expand Down Expand Up @@ -1030,6 +1052,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {

// Deny *any* live drops anywhere other than functions.
if self.mode != Mode::Fn {
unleash_miri!(self);
// HACK(eddyb): emulate a bit of dataflow analysis,
// conservatively, that drop elaboration will do.
let needs_drop = if let Place::Local(local) = *place {
Expand Down Expand Up @@ -1175,7 +1198,9 @@ impl MirPass for QualifyAndPromoteConstants {
let (temps, candidates) = {
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
if mode == Mode::ConstFn {
if tcx.is_min_const_fn(def_id) {
if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
qualifier.qualify_const();
} else if tcx.is_min_const_fn(def_id) {
// enforce `min_const_fn` for stable const fns
use super::qualify_min_const_fn::is_min_const_fn;
if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
Expand Down
30 changes: 30 additions & 0 deletions src/test/ui/consts/miri_unleashed/assoc_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
#![allow(const_err)]

// a test demonstrating why we do need to run static const qualification on associated constants
// instead of just checking the final constant

trait Foo<T> {
const X: T;
}

trait Bar<T, U: Foo<T>> {
const F: u32 = (U::X, 42).1; //~ WARN skipping const checks
}

impl Foo<u32> for () {
const X: u32 = 42;
}
impl Foo<Vec<u32>> for String {
const X: Vec<u32> = Vec::new();
}

impl Bar<u32, ()> for () {}
impl Bar<Vec<u32>, String> for String {}

fn main() {
// this is fine, but would have been forbidden by the static checks on `F`
let x = <() as Bar<u32, ()>>::F;
// this test only causes errors due to the line below, so post-monomorphization
let y = <String as Bar<Vec<u32>, String>>::F; //~ ERROR erroneous constant
}
15 changes: 15 additions & 0 deletions src/test/ui/consts/miri_unleashed/assoc_const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
warning: skipping const checks
--> $DIR/assoc_const.rs:12:31
|
LL | const F: u32 = (U::X, 42).1; //~ WARN skipping const checks
| ^

error[E0080]: erroneous constant used
--> $DIR/assoc_const.rs:29:13
|
LL | let y = <String as Bar<Vec<u32>, String>>::F; //~ ERROR erroneous constant
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors

error: aborting due to previous error

For more information about this error, try `rustc --explain E0080`.
28 changes: 28 additions & 0 deletions src/test/ui/consts/miri_unleashed/assoc_const_2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![allow(const_err)]

// a test demonstrating that const qualification cannot prevent monomorphization time errors

trait Foo {
const X: u32;
}

trait Bar<U: Foo> {
const F: u32 = 100 / U::X;
}

impl Foo for () {
const X: u32 = 42;
}

impl Foo for String {
const X: u32 = 0;
}

impl Bar<()> for () {}
impl Bar<String> for String {}

fn main() {
let x = <() as Bar<()>>::F;
// this test only causes errors due to the line below, so post-monomorphization
let y = <String as Bar<String>>::F; //~ ERROR erroneous constant
}
9 changes: 9 additions & 0 deletions src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0080]: erroneous constant used
--> $DIR/assoc_const_2.rs:27:13
|
LL | let y = <String as Bar<String>>::F; //~ ERROR erroneous constant
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Has errors" is not very precise, why does it not show an actual miri error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of allow(const_err) silencing the lint that reports the error on a constant


error: aborting due to previous error

For more information about this error, try `rustc --explain E0080`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![allow(const_err)]

// a test demonstrating why we do need to run static const qualification on associated constants
// instead of just checking the final constant

trait Foo<T> {
const X: T;
}

trait Bar<T, U: Foo<T>> {
const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time
}

impl Foo<u32> for () {
const X: u32 = 42;
}
impl Foo<Vec<u32>> for String {
const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
}

impl Bar<u32, ()> for () {}
impl Bar<Vec<u32>, String> for String {}

fn main() {
let x = <() as Bar<u32, ()>>::F;
let y = <String as Bar<Vec<u32>, String>>::F;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
|
LL | const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time
| ^^^^^^^^^^ constants cannot evaluate destructors

error: `<std::vec::Vec<T>>::new` is not yet stable as a const fn
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25
|
LL | const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
| ^^^^^^^^^^
|
= help: add `#![feature(const_vec_new)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0493`.