Auto merge of #43568 - arielb1:constant-recovery, r=eddyb

trans::mir::constant - fix assignment error recovery

trans::mir::constant - fix assignment error recovery

We used to not store anything when the RHS of an assignment returned an error, which caused ICEs downstream.

Fixes #43197.
This commit is contained in:
bors 2017-08-01 14:20:23 +00:00
commit c2407516ff
7 changed files with 109 additions and 37 deletions

View File

@ -82,26 +82,27 @@ impl<'a> DiagnosticBuilder<'a> {
return;
}
match self.level {
let is_error = match self.level {
Level::Bug |
Level::Fatal |
Level::PhaseFatal |
Level::Error => {
self.handler.bump_err_count();
true
}
Level::Warning |
Level::Note |
Level::Help |
Level::Cancelled => {
false
}
}
};
self.handler.emitter.borrow_mut().emit(&self);
self.cancel();
if self.level == Level::Error {
self.handler.panic_if_treat_err_as_bug();
if is_error {
self.handler.bump_err_count();
}
// if self.is_fatal() {
@ -210,4 +211,3 @@ impl<'a> Drop for DiagnosticBuilder<'a> {
}
}
}

View File

@ -399,7 +399,6 @@ impl Handler {
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
self.emit(&sp.into(), msg, Fatal);
self.panic_if_treat_err_as_bug();
FatalError
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
@ -408,12 +407,10 @@ impl Handler {
code: &str)
-> FatalError {
self.emit_with_code(&sp.into(), msg, code, Fatal);
self.panic_if_treat_err_as_bug();
FatalError
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Error);
self.panic_if_treat_err_as_bug();
}
pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
@ -425,7 +422,6 @@ impl Handler {
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
self.emit_with_code(&sp.into(), msg, code, Error);
self.panic_if_treat_err_as_bug();
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Warning);
@ -494,6 +490,7 @@ impl Handler {
}
pub fn bump_err_count(&self) {
self.panic_if_treat_err_as_bug();
self.err_count.set(self.err_count.get() + 1);
}

View File

@ -222,15 +222,24 @@ struct MirConstContext<'a, 'tcx: 'a> {
substs: &'tcx Substs<'tcx>,
/// Values of locals in a constant or const fn.
locals: IndexVec<mir::Local, Option<Const<'tcx>>>
locals: IndexVec<mir::Local, Option<Result<Const<'tcx>, ConstEvalErr<'tcx>>>>
}
fn add_err<'tcx, U, V>(failure: &mut Result<U, ConstEvalErr<'tcx>>,
value: &Result<V, ConstEvalErr<'tcx>>)
{
if let &Err(ref err) = value {
if failure.is_ok() {
*failure = Err(err.clone());
}
}
}
impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn new(ccx: &'a CrateContext<'a, 'tcx>,
mir: &'a mir::Mir<'tcx>,
substs: &'tcx Substs<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-> MirConstContext<'a, 'tcx> {
let mut context = MirConstContext {
ccx: ccx,
@ -249,7 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
let instance = monomorphize::resolve(ccx.shared(), def_id, substs);
let mir = ccx.tcx().instance_mir(instance.def);
@ -278,10 +287,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
mir::StatementKind::Assign(ref dest, ref rvalue) => {
let ty = dest.ty(self.mir, tcx);
let ty = self.monomorphize(&ty).to_ty(tcx);
match self.const_rvalue(rvalue, ty, span) {
Ok(value) => self.store(dest, value, span),
Err(err) => if failure.is_ok() { failure = Err(err); }
}
let value = self.const_rvalue(rvalue, ty, span);
add_err(&mut failure, &value);
self.store(dest, value, span);
}
mir::StatementKind::StorageLive(_) |
mir::StatementKind::StorageDead(_) |
@ -301,9 +309,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
mir::TerminatorKind::Goto { target } => target,
mir::TerminatorKind::Return => {
failure?;
return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
return self.locals[mir::RETURN_POINTER].clone().unwrap_or_else(|| {
span_bug!(span, "no returned value in constant");
}));
});
}
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
@ -342,33 +350,30 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let mut arg_vals = IndexVec::with_capacity(args.len());
for arg in args {
match self.const_operand(arg, span) {
Ok(arg) => { arg_vals.push(arg); },
Err(err) => if failure.is_ok() { failure = Err(err); }
}
let arg_val = self.const_operand(arg, span);
add_err(&mut failure, &arg_val);
arg_vals.push(arg_val);
}
if let Some((ref dest, target)) = *destination {
if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
let value = match &tcx.item_name(def_id).as_str()[..] {
let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
match &tcx.item_name(def_id).as_str()[..] {
"size_of" => {
let llval = C_uint(self.ccx,
self.ccx.size_of(substs.type_at(0)));
Const::new(llval, tcx.types.usize)
Ok(Const::new(llval, tcx.types.usize))
}
"min_align_of" => {
let llval = C_uint(self.ccx,
self.ccx.align_of(substs.type_at(0)));
Const::new(llval, tcx.types.usize)
Ok(Const::new(llval, tcx.types.usize))
}
_ => span_bug!(span, "{:?} in constant", terminator.kind)
};
self.store(dest, value, span);
} else {
match MirConstContext::trans_def(self.ccx, def_id, substs, arg_vals) {
Ok(value) => self.store(dest, value, span),
Err(err) => if failure.is_ok() { failure = Err(err); }
}
}
} else {
MirConstContext::trans_def(self.ccx, def_id, substs, arg_vals)
};
add_err(&mut failure, &result);
self.store(dest, result, span);
target
} else {
span_bug!(span, "diverging {:?} in constant", terminator.kind);
@ -379,7 +384,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
}
fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
fn store(&mut self,
dest: &mir::Lvalue<'tcx>,
value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,
span: Span) {
if let mir::Lvalue::Local(index) = *dest {
self.locals[index] = Some(value);
} else {
@ -392,9 +400,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let tcx = self.ccx.tcx();
if let mir::Lvalue::Local(index) = *lvalue {
return Ok(self.locals[index].unwrap_or_else(|| {
return self.locals[index].clone().unwrap_or_else(|| {
span_bug!(span, "{:?} not initialized", lvalue)
}).as_lvalue());
}).map(|v| v.as_lvalue());
}
let lvalue = match *lvalue {

View File

@ -0,0 +1,5 @@
-include ../tools.mk
all:
$(RUSTC) err.rs -Z treat-err-as-bug 2>&1 \
| grep -q "panicked at 'encountered error with .-Z treat_err_as_bug'"

View File

@ -0,0 +1,13 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_type="rlib"]
pub static C: u32 = 0-1;

View File

@ -0,0 +1,21 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(const_fn)]
const fn foo(x: u32) -> u32 {
x
}
fn main() {
const X: u32 = 0-1;
const Y: u32 = foo(0-1);
println!("{} {}", X, Y);
}

View File

@ -0,0 +1,28 @@
warning: constant evaluation error: attempt to subtract with overflow. This will become a HARD ERROR in the future
--> $DIR/issue-43197.rs:18:20
|
18 | const X: u32 = 0-1;
| ^^^
|
= note: #[warn(const_err)] on by default
warning: constant evaluation error: attempt to subtract with overflow. This will become a HARD ERROR in the future
--> $DIR/issue-43197.rs:19:20
|
19 | const Y: u32 = foo(0-1);
| ^^^^^^^^
error[E0080]: constant evaluation error
--> $DIR/issue-43197.rs:18:20
|
18 | const X: u32 = 0-1;
| ^^^ attempt to subtract with overflow
error[E0080]: constant evaluation error
--> $DIR/issue-43197.rs:19:24
|
19 | const Y: u32 = foo(0-1);
| ^^^ attempt to subtract with overflow
error: aborting due to 2 previous errors