From 944237f6cd2b7e732b6875bf0956bf323cc3316b Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 24 Jan 2021 12:12:08 +0100
Subject: [PATCH] codegen: assume constants cannot fail to evaluate

also don't submit code to LLVM when the session has errors
---
 compiler/rustc_codegen_ssa/src/base.rs        |  5 ++++
 compiler/rustc_codegen_ssa/src/mir/mod.rs     |  8 ++++++
 compiler/rustc_codegen_ssa/src/mir/operand.rs | 25 +++----------------
 compiler/rustc_mir/src/interpret/operand.rs   |  4 +++
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 2ce5fe5ad504b..5cb0b03a4ba85 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -625,6 +625,11 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                         *time += start_time.elapsed();
                         module
                     };
+                // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
+                // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
+                // compilation hang on post-monomorphization errors.
+                tcx.sess.abort_if_errors();
+
                 submit_codegened_module_to_llvm(
                     &backend,
                     &ongoing_codegen.coordinator_send,
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 285140060be45..d31ececf13062 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -188,8 +188,11 @@ 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);
 
+    // Evaluate all required consts; codegen later assumes that CTFE will never fail.
+    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 => {}
@@ -199,6 +202,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             }
         }
     }
+    if !all_consts_ok {
+        // We leave the IR in some half-built state here, and rely on this code not even being
+        // submitted to LLVM once an error was raised.
+        return;
+    }
 
     let memory_locals = analyze::non_ssa_locals(&fx);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 08a4ae3962bee..25e84c38ed315 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -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};
@@ -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")
                 })
             }
         }
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index d9437a312aec0..88236458a213a 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -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)?
             }
         };