From 93db1f9923d23c905c5cd8e7c50c5927c7c72a24 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 31 Jul 2017 17:42:42 +0300 Subject: [PATCH] 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. --- src/librustc_trans/mir/constant.rs | 62 +++++++++++++---------- src/test/ui/const-eval/issue-43197.rs | 21 ++++++++ src/test/ui/const-eval/issue-43197.stderr | 28 ++++++++++ 3 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/const-eval/issue-43197.rs create mode 100644 src/test/ui/const-eval/issue-43197.stderr diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 98e774a2987..393fa9c0c8e 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -222,15 +222,24 @@ struct MirConstContext<'a, 'tcx: 'a> { substs: &'tcx Substs<'tcx>, /// Values of locals in a constant or const fn. - locals: IndexVec>> + locals: IndexVec, ConstEvalErr<'tcx>>>> } +fn add_err<'tcx, U, V>(failure: &mut Result>, + value: &Result>) +{ + 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>) + args: IndexVec, ConstEvalErr<'tcx>>>) -> MirConstContext<'a, 'tcx> { let mut context = MirConstContext { ccx: ccx, @@ -249,7 +258,7 @@ fn new(ccx: &'a CrateContext<'a, 'tcx>, fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, - args: IndexVec>) + args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { let instance = monomorphize::resolve(ccx.shared(), def_id, substs); let mir = ccx.tcx().instance_mir(instance.def); @@ -278,10 +287,9 @@ fn trans(&mut self) -> Result, ConstEvalErr<'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 @@ fn trans(&mut self) -> Result, ConstEvalErr<'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 @@ fn trans(&mut self) -> Result, ConstEvalErr<'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 @@ fn trans(&mut self) -> Result, ConstEvalErr<'tcx>> { } } - fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) { + fn store(&mut self, + dest: &mir::Lvalue<'tcx>, + value: Result, ConstEvalErr<'tcx>>, + span: Span) { if let mir::Lvalue::Local(index) = *dest { self.locals[index] = Some(value); } else { @@ -392,9 +400,9 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) 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 { diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs new file mode 100644 index 00000000000..1d4ded6e712 --- /dev/null +++ b/src/test/ui/const-eval/issue-43197.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr new file mode 100644 index 00000000000..5ff80060eac --- /dev/null +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -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 +