Skip to content

Commit 93db1f9

Browse files
committed
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.
1 parent 1057a72 commit 93db1f9

File tree

3 files changed

+84
-27
lines changed

3 files changed

+84
-27
lines changed

src/librustc_trans/mir/constant.rs

+35-27
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,24 @@ struct MirConstContext<'a, 'tcx: 'a> {
222222
substs: &'tcx Substs<'tcx>,
223223

224224
/// Values of locals in a constant or const fn.
225-
locals: IndexVec<mir::Local, Option<Const<'tcx>>>
225+
locals: IndexVec<mir::Local, Option<Result<Const<'tcx>, ConstEvalErr<'tcx>>>>
226226
}
227227

228+
fn add_err<'tcx, U, V>(failure: &mut Result<U, ConstEvalErr<'tcx>>,
229+
value: &Result<V, ConstEvalErr<'tcx>>)
230+
{
231+
if let &Err(ref err) = value {
232+
if failure.is_ok() {
233+
*failure = Err(err.clone());
234+
}
235+
}
236+
}
228237

229238
impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
230239
fn new(ccx: &'a CrateContext<'a, 'tcx>,
231240
mir: &'a mir::Mir<'tcx>,
232241
substs: &'tcx Substs<'tcx>,
233-
args: IndexVec<mir::Local, Const<'tcx>>)
242+
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
234243
-> MirConstContext<'a, 'tcx> {
235244
let mut context = MirConstContext {
236245
ccx: ccx,
@@ -249,7 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
249258
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
250259
def_id: DefId,
251260
substs: &'tcx Substs<'tcx>,
252-
args: IndexVec<mir::Local, Const<'tcx>>)
261+
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
253262
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
254263
let instance = monomorphize::resolve(ccx.shared(), def_id, substs);
255264
let mir = ccx.tcx().instance_mir(instance.def);
@@ -278,10 +287,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
278287
mir::StatementKind::Assign(ref dest, ref rvalue) => {
279288
let ty = dest.ty(self.mir, tcx);
280289
let ty = self.monomorphize(&ty).to_ty(tcx);
281-
match self.const_rvalue(rvalue, ty, span) {
282-
Ok(value) => self.store(dest, value, span),
283-
Err(err) => if failure.is_ok() { failure = Err(err); }
284-
}
290+
let value = self.const_rvalue(rvalue, ty, span);
291+
add_err(&mut failure, &value);
292+
self.store(dest, value, span);
285293
}
286294
mir::StatementKind::StorageLive(_) |
287295
mir::StatementKind::StorageDead(_) |
@@ -301,9 +309,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
301309
mir::TerminatorKind::Goto { target } => target,
302310
mir::TerminatorKind::Return => {
303311
failure?;
304-
return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
312+
return self.locals[mir::RETURN_POINTER].clone().unwrap_or_else(|| {
305313
span_bug!(span, "no returned value in constant");
306-
}));
314+
});
307315
}
308316

309317
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
@@ -342,33 +350,30 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
342350

343351
let mut arg_vals = IndexVec::with_capacity(args.len());
344352
for arg in args {
345-
match self.const_operand(arg, span) {
346-
Ok(arg) => { arg_vals.push(arg); },
347-
Err(err) => if failure.is_ok() { failure = Err(err); }
348-
}
353+
let arg_val = self.const_operand(arg, span);
354+
add_err(&mut failure, &arg_val);
355+
arg_vals.push(arg_val);
349356
}
350357
if let Some((ref dest, target)) = *destination {
351-
if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
352-
let value = match &tcx.item_name(def_id).as_str()[..] {
358+
let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
359+
match &tcx.item_name(def_id).as_str()[..] {
353360
"size_of" => {
354361
let llval = C_uint(self.ccx,
355362
self.ccx.size_of(substs.type_at(0)));
356-
Const::new(llval, tcx.types.usize)
363+
Ok(Const::new(llval, tcx.types.usize))
357364
}
358365
"min_align_of" => {
359366
let llval = C_uint(self.ccx,
360367
self.ccx.align_of(substs.type_at(0)));
361-
Const::new(llval, tcx.types.usize)
368+
Ok(Const::new(llval, tcx.types.usize))
362369
}
363370
_ => span_bug!(span, "{:?} in constant", terminator.kind)
364-
};
365-
self.store(dest, value, span);
366-
} else {
367-
match MirConstContext::trans_def(self.ccx, def_id, substs, arg_vals) {
368-
Ok(value) => self.store(dest, value, span),
369-
Err(err) => if failure.is_ok() { failure = Err(err); }
370371
}
371-
}
372+
} else {
373+
MirConstContext::trans_def(self.ccx, def_id, substs, arg_vals)
374+
};
375+
add_err(&mut failure, &result);
376+
self.store(dest, result, span);
372377
target
373378
} else {
374379
span_bug!(span, "diverging {:?} in constant", terminator.kind);
@@ -379,7 +384,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
379384
}
380385
}
381386

382-
fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
387+
fn store(&mut self,
388+
dest: &mir::Lvalue<'tcx>,
389+
value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,
390+
span: Span) {
383391
if let mir::Lvalue::Local(index) = *dest {
384392
self.locals[index] = Some(value);
385393
} else {
@@ -392,9 +400,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
392400
let tcx = self.ccx.tcx();
393401

394402
if let mir::Lvalue::Local(index) = *lvalue {
395-
return Ok(self.locals[index].unwrap_or_else(|| {
403+
return self.locals[index].clone().unwrap_or_else(|| {
396404
span_bug!(span, "{:?} not initialized", lvalue)
397-
}).as_lvalue());
405+
}).map(|v| v.as_lvalue());
398406
}
399407

400408
let lvalue = match *lvalue {

src/test/ui/const-eval/issue-43197.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(const_fn)]
12+
13+
const fn foo(x: u32) -> u32 {
14+
x
15+
}
16+
17+
fn main() {
18+
const X: u32 = 0-1;
19+
const Y: u32 = foo(0-1);
20+
println!("{} {}", X, Y);
21+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
warning: constant evaluation error: attempt to subtract with overflow. This will become a HARD ERROR in the future
2+
--> $DIR/issue-43197.rs:18:20
3+
|
4+
18 | const X: u32 = 0-1;
5+
| ^^^
6+
|
7+
= note: #[warn(const_err)] on by default
8+
9+
warning: constant evaluation error: attempt to subtract with overflow. This will become a HARD ERROR in the future
10+
--> $DIR/issue-43197.rs:19:20
11+
|
12+
19 | const Y: u32 = foo(0-1);
13+
| ^^^^^^^^
14+
15+
error[E0080]: constant evaluation error
16+
--> $DIR/issue-43197.rs:18:20
17+
|
18+
18 | const X: u32 = 0-1;
19+
| ^^^ attempt to subtract with overflow
20+
21+
error[E0080]: constant evaluation error
22+
--> $DIR/issue-43197.rs:19:24
23+
|
24+
19 | const Y: u32 = foo(0-1);
25+
| ^^^ attempt to subtract with overflow
26+
27+
error: aborting due to 2 previous errors
28+

0 commit comments

Comments
 (0)