about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2018-11-21 10:54:46 +0100
committerOliver Scherer <github35764891676564198441@oli-obk.de>2019-01-31 14:03:01 +0100
commitd0129a613c3bd4581826bb838eea1ab96c2cd5c7 (patch)
treeffa2c04e3a1e89bdaea9d91976d87232cffc8e17
parentf40aaa68278ef0879af5fe7ce077c64c6515ea05 (diff)
downloadrust-d0129a613c3bd4581826bb838eea1ab96c2cd5c7.tar.gz
rust-d0129a613c3bd4581826bb838eea1ab96c2cd5c7.zip
Add a forever unstable opt-out of const qualification checks
-rw-r--r--src/librustc/session/config.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs29
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const.rs30
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const.stderr15
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const_2.rs28
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const_2.stderr9
-rw-r--r--src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs27
-rw-r--r--src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr17
8 files changed, 155 insertions, 2 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 4b1aefb2216..577246783a1 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -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],
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2d941902deb..7d1943e21b9 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -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,
@@ -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!(
@@ -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 {
@@ -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,
@@ -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.
@@ -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);
@@ -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);
@@ -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,
@@ -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.
@@ -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 {
@@ -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) {
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.rs b/src/test/ui/consts/miri_unleashed/assoc_const.rs
new file mode 100644
index 00000000000..b8959667cc2
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/assoc_const.rs
@@ -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
+}
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.stderr b/src/test/ui/consts/miri_unleashed/assoc_const.stderr
new file mode 100644
index 00000000000..a40f8d46d0a
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/assoc_const.stderr
@@ -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`.
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const_2.rs b/src/test/ui/consts/miri_unleashed/assoc_const_2.rs
new file mode 100644
index 00000000000..c87b6389848
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/assoc_const_2.rs
@@ -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
+}
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
new file mode 100644
index 00000000000..77aab31d26e
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
@@ -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
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
new file mode 100644
index 00000000000..5fb92535502
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
@@ -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;
+}
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
new file mode 100644
index 00000000000..e23ed1c6206
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
@@ -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`.