Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -210,4 +211,3 @@ impl<'a> Drop for DiagnosticBuilder<'a> {
}
}
}

5 changes: 1 addition & 4 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
62 changes: 35 additions & 27 deletions src/librustc_trans/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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(_) |
Expand All @@ -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, .. } => {
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions src/test/run-make/treat-err-as-bug/Makefile
Original file line number Diff line number Diff line change
@@ -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'"
13 changes: 13 additions & 0 deletions src/test/run-make/treat-err-as-bug/err.rs
Original file line number Diff line number Diff line change
@@ -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;
21 changes: 21 additions & 0 deletions src/test/ui/const-eval/issue-43197.rs
Original file line number Diff line number Diff line change
@@ -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);
}
28 changes: 28 additions & 0 deletions src/test/ui/const-eval/issue-43197.stderr
Original file line number Diff line number Diff line change
@@ -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