diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3968d9aece21..faecb7013b49 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, 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 d6aeb288b5cd..1d28c4fa114e 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 b058748fca02..81cccd9fd530 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( + 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::BitOr, lhs: lhs.to_ref(), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 76dde4ed02bc..a7924b7b7387 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 5a08165608d5..9d90dc2931af 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 3a0094bcd625..15a82fcadc1f 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 0f174d6da1fc..e49134409f0c 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 2d278d115d5b..54e0e83efed3 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 e644886b923e..cc49e4696e58 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 4c1e531ea872..6f8fca60c809 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