about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/mod.rs6
-rw-r--r--src/librustc/ty/structural_impls.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs29
-rw-r--r--src/librustc_mir/hair/cx/mod.rs6
-rw-r--r--src/librustc_mir/shim.rs8
-rw-r--r--src/librustc_mir/transform/promote_consts.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs25
-rw-r--r--src/test/run-pass/ctfe/issue-37550.rs2
-rw-r--r--src/test/ui/consts/const_short_circuit.rs12
-rw-r--r--src/test/ui/consts/const_short_circuit.stderr42
10 files changed, 61 insertions, 72 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 3968d9aece2..faecb7013b4 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -153,7 +153,9 @@ pub struct Mir<'tcx> {
     /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
     /// this conversion from happening and use short circuiting, we will cause the following code
     /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };`
-    pub control_flow_destroyed: bool,
+    ///
+    /// List of places where control flow was destroyed. Used for error reporting.
+    pub control_flow_destroyed: Vec<(Span, String)>,
 
     /// A span representing this MIR, for error reporting
     pub span: Span,
@@ -173,7 +175,7 @@ impl<'tcx> Mir<'tcx> {
         arg_count: usize,
         upvar_decls: Vec<UpvarDecl>,
         span: Span,
-        control_flow_destroyed: bool,
+        control_flow_destroyed: Vec<(Span, String)>,
     ) -> Self {
         // We need `arg_count` locals, and one for the return place
         assert!(
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index d6aeb288b5c..1d28c4fa114 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -35,6 +35,7 @@ CloneTypeFoldableAndLiftImpls! {
     usize,
     ::ty::layout::VariantIdx,
     u64,
+    String,
     ::middle::region::Scope,
     ::syntax::ast::FloatTy,
     ::syntax::ast::NodeId,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index b058748fca0..81cccd9fd53 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -23,7 +23,6 @@ use rustc::hir;
 use rustc::hir::def_id::LocalDefId;
 use rustc::mir::{BorrowKind};
 use syntax_pos::Span;
-use syntax::errors::Applicability;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
@@ -373,18 +372,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     // FIXME(eddyb) use logical ops in constants when
                     // they can handle that kind of control-flow.
                     (hir::BinOpKind::And, hir::Constness::Const) => {
-                        cx.control_flow_destroyed = true;
-                        cx.tcx.sess.struct_span_warn(
+                        cx.control_flow_destroyed.push((
                             op.span,
-                            "boolean short circuiting operators in constants do \
-                             not actually short circuit. Thus new const eval features \
-                             are not accessible in constants."
-                        ).span_suggestion_with_applicability(
-                            op.span,
-                            "use a bit operator instead",
-                            "&".into(),
-                            Applicability::MachineApplicable,
-                        ).emit();
+                            "`&&` operator".into(),
+                        ));
                         ExprKind::Binary {
                             op: BinOp::BitAnd,
                             lhs: lhs.to_ref(),
@@ -392,18 +383,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         }
                     }
                     (hir::BinOpKind::Or, hir::Constness::Const) => {
-                        cx.control_flow_destroyed = true;
-                        cx.tcx.sess.struct_span_warn(
-                            op.span,
-                            "boolean short circuiting operators in constants do \
-                             not actually short circuit. Thus new const eval features \
-                             are not accessible in constants."
-                        ).span_suggestion_with_applicability(
+                        cx.control_flow_destroyed.push((
                             op.span,
-                            "use a bit operator instead",
-                            "|".into(),
-                            Applicability::MachineApplicable,
-                        ).emit();
+                            "`||` operator".into(),
+                        ));
                         ExprKind::Binary {
                             op: BinOp::BitOr,
                             lhs: lhs.to_ref(),
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 76dde4ed02b..a7924b7b738 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -58,7 +58,7 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     check_overflow: bool,
 
     /// See field with the same name on `Mir`
-    control_flow_destroyed: bool,
+    control_flow_destroyed: Vec<(Span, String)>,
 }
 
 impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
@@ -99,11 +99,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             constness,
             body_owner_kind,
             check_overflow,
-            control_flow_destroyed: false,
+            control_flow_destroyed: Vec::new(),
         }
     }
 
-    pub fn control_flow_destroyed(&self) -> bool {
+    pub fn control_flow_destroyed(self) -> Vec<(Span, String)> {
         self.control_flow_destroyed
     }
 }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 5a08165608d..9d90dc2931a 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -220,7 +220,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         sig.inputs().len(),
         vec![],
         span,
-        true,
+        vec![],
     );
 
     if let Some(..) = ty {
@@ -389,7 +389,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             self.sig.inputs().len(),
             vec![],
             self.span,
-            true,
+            vec![],
         )
     }
 
@@ -838,7 +838,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         sig.inputs().len(),
         vec![],
         span,
-        true,
+        vec![],
     );
     if let Abi::RustCall = sig.abi {
         mir.spread_arg = Some(Local::new(sig.inputs().len()));
@@ -916,6 +916,6 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         sig.inputs().len(),
         vec![],
         span,
-        true,
+        vec![],
     )
 }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 3a0094bcd62..15a82fcadc1 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -413,7 +413,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 0,
                 vec![],
                 mir.span,
-                false,
+                vec![],
             ),
             tcx,
             source: mir,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 0f174d6da1f..e49134409f0 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1335,17 +1335,32 @@ impl MirPass for QualifyAndPromoteConstants {
             // Do the actual promotion, now that we know what's viable.
             promote_consts::promote_candidates(mir, tcx, temps, candidates);
         } else {
-            if mir.control_flow_destroyed {
-                for local in mir.vars_iter() {
+            if !mir.control_flow_destroyed.is_empty() {
+                let mut locals = mir.vars_iter();
+                if let Some(local) = locals.next() {
                     let span = mir.local_decls[local].source_info.span;
-                    tcx.sess.span_err(
+                    let mut error = tcx.sess.struct_span_err(
                         span,
                         &format!(
-                            "short circuiting operators do not actually short circuit in {}. \
-                             Thus new features like let bindings are not permitted",
+                            "new features like let bindings are not permitted in {} \
+                            which also use short circuiting operators",
                             mode,
                         ),
                     );
+                    for (span, kind) in mir.control_flow_destroyed.iter() {
+                        error.span_note(
+                            *span,
+                            &format!("use of {} here", kind),
+                        );
+                    }
+                    for local in locals {
+                        let span = mir.local_decls[local].source_info.span;
+                        error.span_note(
+                            span,
+                            "more locals defined here",
+                        );
+                    }
+                    error.emit();
                 }
             }
             let promoted_temps = if mode == Mode::Const {
diff --git a/src/test/run-pass/ctfe/issue-37550.rs b/src/test/run-pass/ctfe/issue-37550.rs
index 2d278d115d5..54e0e83efed 100644
--- a/src/test/run-pass/ctfe/issue-37550.rs
+++ b/src/test/run-pass/ctfe/issue-37550.rs
@@ -12,7 +12,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(const_fn)]
+#![feature(const_fn, const_let)]
 
 const fn x() {
     let t = true;
diff --git a/src/test/ui/consts/const_short_circuit.rs b/src/test/ui/consts/const_short_circuit.rs
index e644886b923..cc49e4696e5 100644
--- a/src/test/ui/consts/const_short_circuit.rs
+++ b/src/test/ui/consts/const_short_circuit.rs
@@ -1,15 +1,15 @@
 #![feature(underscore_const_names, const_let)]
 
-const _: bool = false && false; //~ WARN boolean short circuiting operators in constants
-const _: bool = true && false; //~ WARN boolean short circuiting operators in constants
+const _: bool = false && false;
+const _: bool = true && false;
 const _: bool = {
-    let mut x = true && false; //~ WARN boolean short circuiting operators in constants
-    //~^ ERROR short circuiting operators do not actually short circuit in constant
+    let mut x = true && false;
+    //~^ ERROR new features like let bindings are not permitted
     x
 };
 const _: bool = {
-    let x = true && false; //~ WARN boolean short circuiting operators in constants
-    //~^ ERROR short circuiting operators do not actually short circuit in constant
+    let x = true && false;
+    //~^ ERROR new features like let bindings are not permitted
     x
 };
 
diff --git a/src/test/ui/consts/const_short_circuit.stderr b/src/test/ui/consts/const_short_circuit.stderr
index 4c1e531ea87..6f8fca60c80 100644
--- a/src/test/ui/consts/const_short_circuit.stderr
+++ b/src/test/ui/consts/const_short_circuit.stderr
@@ -1,38 +1,26 @@
-warning: boolean short circuiting operators in constants do not actually short circuit. Thus new const eval features are not accessible in constants.
-  --> $DIR/const_short_circuit.rs:3:23
-   |
-LL | const _: bool = false && false; //~ WARN boolean short circuiting operators in constants
-   |                       ^^ help: use a bit operator instead: `&`
-
-warning: boolean short circuiting operators in constants do not actually short circuit. Thus new const eval features are not accessible in constants.
-  --> $DIR/const_short_circuit.rs:4:22
-   |
-LL | const _: bool = true && false; //~ WARN boolean short circuiting operators in constants
-   |                      ^^ help: use a bit operator instead: `&`
-
-warning: boolean short circuiting operators in constants do not actually short circuit. Thus new const eval features are not accessible in constants.
-  --> $DIR/const_short_circuit.rs:6:22
-   |
-LL |     let mut x = true && false; //~ WARN boolean short circuiting operators in constants
-   |                      ^^ help: use a bit operator instead: `&`
-
-error: short circuiting operators do not actually short circuit in constant. Thus new features like let bindings are not permitted
+error: new features like let bindings are not permitted in constant which also use short circuiting operators
   --> $DIR/const_short_circuit.rs:6:9
    |
-LL |     let mut x = true && false; //~ WARN boolean short circuiting operators in constants
+LL |     let mut x = true && false;
    |         ^^^^^
-
-warning: boolean short circuiting operators in constants do not actually short circuit. Thus new const eval features are not accessible in constants.
-  --> $DIR/const_short_circuit.rs:11:18
    |
-LL |     let x = true && false; //~ WARN boolean short circuiting operators in constants
-   |                  ^^ help: use a bit operator instead: `&`
+note: use of `&&` operator here
+  --> $DIR/const_short_circuit.rs:6:22
+   |
+LL |     let mut x = true && false;
+   |                      ^^
 
-error: short circuiting operators do not actually short circuit in constant. Thus new features like let bindings are not permitted
+error: new features like let bindings are not permitted in constant which also use short circuiting operators
   --> $DIR/const_short_circuit.rs:11:9
    |
-LL |     let x = true && false; //~ WARN boolean short circuiting operators in constants
+LL |     let x = true && false;
    |         ^
+   |
+note: use of `&&` operator here
+  --> $DIR/const_short_circuit.rs:11:18
+   |
+LL |     let x = true && false;
+   |                  ^^
 
 error: aborting due to 2 previous errors