Skip to content

Commit

Permalink
codegen: assume constants cannot fail to evaluate
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jan 24, 2021
1 parent 4d0dd02 commit 6d4e03a
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 21 deletions.
21 changes: 21 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);

let mut all_consts_ok = true;
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {
all_consts_ok = false;
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
Expand All @@ -199,6 +201,25 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
}
if !all_consts_ok {
// There is no delay_span_bug here, we just have to rely on a hard error actually having
// been raised.
bx.abort();
// `abort` does not terminate the block, so we still need to generate
// an `unreachable` terminator after it.
bx.unreachable();
// We also have to delete all the other basic blocks again...
for bb in mir.basic_blocks().indices() {
if bb != mir::START_BLOCK {
unsafe {
bx.delete_basic_block(fx.blocks[bb]);
}
}
}
// FIXME: Can we somehow avoid all this by evaluating the consts before creating the basic
// blocks? The tricky part is doing that without duplicating `fx.eval_mir_constant`.
return;
}

let memory_locals = analyze::non_ssa_locals(&fx);

Expand Down
25 changes: 4 additions & 21 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use crate::glue;
use crate::traits::*;
use crate::MemFlags;

use rustc_errors::ErrorReported;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::Ty;
use rustc_target::abi::{Abi, Align, LayoutOf, Size};
Expand Down Expand Up @@ -439,25 +438,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}

mir::Operand::Constant(ref constant) => {
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| {
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
bug!("codegen encountered polymorphic constant")
}
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB.
bx.abort();
// We still have to return an operand but it doesn't matter,
// this code is unreachable.
let ty = self.monomorphize(constant.literal.ty);
let layout = bx.cx().layout_of(ty);
bx.load_operand(PlaceRef::new_sized(
bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
layout,
))
// This cannot fail because we checked all required_consts in advance.
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
span_bug!(constant.span, "erroneous constant not captured by required_consts")
})
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Constant(ref constant) => {
let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
// This can still fail:
// * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
// checked yet.
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
self.const_to_op(val, layout)?
}
};
Expand Down

0 comments on commit 6d4e03a

Please sign in to comment.