Improve the diagnostic message

This commit is contained in:
Oliver Scherer 2018-11-26 17:30:19 +01:00
parent 8937faa837
commit 16d2a92b3d
10 changed files with 61 additions and 72 deletions

View File

@ -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 @@ pub fn new(
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!(

View File

@ -35,6 +35,7 @@
usize,
::ty::layout::VariantIdx,
u64,
String,
::middle::region::Scope,
::syntax::ast::FloatTy,
::syntax::ast::NodeId,

View File

@ -23,7 +23,6 @@
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(),

View File

@ -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 @@ pub fn new(infcx: &'a InferCtxt<'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
}
}

View File

@ -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 @@ fn into_mir(self) -> Mir<'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![],
)
}

View File

@ -413,7 +413,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
0,
vec![],
mir.span,
false,
vec![],
),
tcx,
source: mir,

View File

@ -1335,17 +1335,32 @@ fn run_pass<'a, 'tcx>(&self,
// 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 {

View File

@ -12,7 +12,7 @@
#![allow(dead_code)]
#![allow(unused_variables)]
#![feature(const_fn)]
#![feature(const_fn, const_let)]
const fn x() {
let t = true;

View File

@ -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
};

View File

@ -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