about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-25 09:35:53 +0000
committerbors <bors@rust-lang.org>2024-06-25 09:35:53 +0000
commitc2d2bb38c9067d983d13505c47e761308b1694db (patch)
tree2fe2616249708698fe3a1a5a21576ebce6996b8e
parentbda221a0eb5019a939e34e0f4583f1c4b6e5b862 (diff)
parent8d1f5b30efc22244f271b82adf4e7e670835432a (diff)
downloadrust-c2d2bb38c9067d983d13505c47e761308b1694db.tar.gz
rust-c2d2bb38c9067d983d13505c47e761308b1694db.zip
Auto merge of #126834 - bjorn3:interface_refactor, r=michaelwoerister
Various refactorings to rustc_interface

This should make it easier to move the driver interface away from queries in the future. Many custom drivers call queries like `queries.global_ctxt()` before they are supposed to be called, breaking some things like certain `--print` and `-Zunpretty` options, `-Zparse-only` and emitting the dep info at the wrong point in time. They are also not actually necessary at all. Passing around the query output manually would avoid recomputation too and would be just as easy. Removing driver queries would also reduce the amount of global mutable state of the compiler. I'm not removing driver queries in this PR to avoid breaking the aforementioned custom drivers.
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs29
-rw-r--r--compiler/rustc_interface/src/interface.rs21
-rw-r--r--compiler/rustc_interface/src/lib.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs145
-rw-r--r--compiler/rustc_interface/src/queries.rs137
-rw-r--r--tests/run-make/jobserver-error/cannot_open_fd.stderr2
-rw-r--r--tests/run-make/no-input-file/rmake.rs10
-rw-r--r--tests/ui/deployment-target/invalid-target.stderr2
8 files changed, 164 insertions, 184 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index f8c68791564..bbe9741bf44 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -30,7 +30,7 @@ use rustc_errors::{
 };
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, get_codegen_backend};
-use rustc_interface::{interface, Queries};
+use rustc_interface::{interface, passes, Queries};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
@@ -367,18 +367,17 @@ fn run_compiler(
             return early_exit();
         }
 
-        let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format);
-
-        if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop {
+        if print_crate_info(codegen_backend, sess, has_input) == Compilation::Stop {
             return early_exit();
         }
 
         if !has_input {
-            early_dcx.early_fatal("no input filename given"); // this is fatal
+            #[allow(rustc::diagnostic_outside_of_impl)]
+            sess.dcx().fatal("no input filename given"); // this is fatal
         }
 
         if !sess.opts.unstable_opts.ls.is_empty() {
-            list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader());
+            list_metadata(sess, &*codegen_backend.metadata_loader());
             return early_exit();
         }
 
@@ -399,7 +398,9 @@ fn run_compiler(
                         Ok(())
                     })?;
 
-                    queries.write_dep_info()?;
+                    queries.global_ctxt()?.enter(|tcx| {
+                        passes::write_dep_info(tcx);
+                    });
                 } else {
                     let krate = queries.parse()?;
                     pretty::print(
@@ -427,7 +428,9 @@ fn run_compiler(
                 return early_exit();
             }
 
-            queries.write_dep_info()?;
+            queries.global_ctxt()?.enter(|tcx| {
+                passes::write_dep_info(tcx);
+            });
 
             if sess.opts.output_types.contains_key(&OutputType::DepInfo)
                 && sess.opts.output_types.len() == 1
@@ -670,7 +673,7 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
     }
 }
 
-fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dyn MetadataLoader) {
+fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) {
     match sess.io.input {
         Input::File(ref ifile) => {
             let path = &(*ifile);
@@ -687,13 +690,13 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
             safe_println!("{}", String::from_utf8(v).unwrap());
         }
         Input::Str { .. } => {
-            early_dcx.early_fatal("cannot list metadata for stdin");
+            #[allow(rustc::diagnostic_outside_of_impl)]
+            sess.dcx().fatal("cannot list metadata for stdin");
         }
     }
 }
 
 fn print_crate_info(
-    early_dcx: &EarlyDiagCtxt,
     codegen_backend: &dyn CodegenBackend,
     sess: &Session,
     parse_attrs: bool,
@@ -877,8 +880,8 @@ fn print_crate_info(
                         .expect("unknown Apple target OS");
                     println_info!("deployment_target={}", format!("{major}.{minor}"))
                 } else {
-                    early_dcx
-                        .early_fatal("only Apple targets currently support deployment version info")
+                    #[allow(rustc::diagnostic_outside_of_impl)]
+                    sess.dcx().fatal("only Apple targets currently support deployment version info")
                 }
             }
         }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 41c8b941717..dba20e4a335 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -495,9 +495,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let res = {
                 // If `f` panics, `finish_diagnostics` will run during
                 // unwinding because of the `defer`.
-                let mut guar = None;
                 let sess_abort_guard = defer(|| {
-                    guar = compiler.sess.finish_diagnostics(&config.registry);
+                    compiler.sess.finish_diagnostics(&config.registry);
                 });
 
                 let res = f(&compiler);
@@ -506,16 +505,14 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 // normally when `sess_abort_guard` is dropped.
                 drop(sess_abort_guard);
 
-                // If `finish_diagnostics` emits errors (e.g. stashed
-                // errors) we can't return an error directly, because the
-                // return type of this function is `R`, not `Result<R, E>`.
-                // But we need to communicate the errors' existence to the
-                // caller, otherwise the caller might mistakenly think that
-                // no errors occurred and return a zero exit code. So we
-                // abort (panic) instead, similar to if `f` had panicked.
-                if guar.is_some() {
-                    compiler.sess.dcx().abort_if_errors();
-                }
+                // If error diagnostics have been emitted, we can't return an
+                // error directly, because the return type of this function
+                // is `R`, not `Result<R, E>`. But we need to communicate the
+                // errors' existence to the caller, otherwise the caller might
+                // mistakenly think that no errors occurred and return a zero
+                // exit code. So we abort (panic) instead, similar to if `f`
+                // had panicked.
+                compiler.sess.dcx().abort_if_errors();
 
                 res
             };
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 0c3d4e19ef8..38f64ebb04e 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -8,7 +8,7 @@
 mod callbacks;
 mod errors;
 pub mod interface;
-mod passes;
+pub mod passes;
 mod proc_macro_decls;
 mod queries;
 pub mod util;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index f881d53858a..2951f50b1f5 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -7,16 +7,16 @@ use rustc_ast::{self as ast, visit};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{Lrc, OnceLock, WorkerLocal};
-use rustc_errors::PResult;
+use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
 use rustc_feature::Features;
 use rustc_fs_util::try_canonicalize;
-use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
+use rustc_hir::def_id::{StableCrateId, StableCrateIdMap, LOCAL_CRATE};
+use rustc_hir::definitions::Definitions;
+use rustc_incremental::setup_dep_graph;
 use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
-use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_parse::{
@@ -28,6 +28,7 @@ use rustc_session::code_stats::VTableSizeInfo;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
 use rustc_session::output::filename_for_input;
+use rustc_session::output::{collect_crate_types, find_crate_name};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
@@ -39,20 +40,22 @@ use std::any::Any;
 use std::ffi::OsString;
 use std::io::{self, BufWriter, Write};
 use std::path::{Path, PathBuf};
-use std::sync::LazyLock;
+use std::sync::{Arc, LazyLock};
 use std::{env, fs, iter};
 use tracing::{info, instrument};
 
-pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
-    let krate = sess.time("parse_crate", || {
-        let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
-            Input::File(file) => new_parser_from_file(&sess.psess, file, None),
-            Input::Str { input, name } => {
-                new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
-            }
-        });
-        parser.parse_crate_mod()
-    })?;
+pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
+    let krate = sess
+        .time("parse_crate", || {
+            let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
+                Input::File(file) => new_parser_from_file(&sess.psess, file, None),
+                Input::Str { input, name } => {
+                    new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
+                }
+            });
+            parser.parse_crate_mod()
+        })
+        .map_err(|parse_error| parse_error.emit())?;
 
     if sess.opts.unstable_opts.input_stats {
         eprintln!("Lines of code:             {}", sess.source_map().count_lines());
@@ -559,7 +562,7 @@ fn resolver_for_lowering_raw<'tcx>(
     (tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate)))), resolutions)
 }
 
-pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) {
+pub fn write_dep_info(tcx: TyCtxt<'_>) {
     // Make sure name resolution and macro expansion is run for
     // the side-effect of providing a complete set of all
     // accessed files and env vars.
@@ -640,22 +643,48 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     *providers
 });
 
-pub fn create_global_ctxt<'tcx>(
+pub(crate) fn create_global_ctxt<'tcx>(
     compiler: &'tcx Compiler,
-    crate_types: Vec<CrateType>,
-    stable_crate_id: StableCrateId,
-    dep_graph: DepGraph,
-    untracked: Untracked,
+    mut krate: rustc_ast::Crate,
     gcx_cell: &'tcx OnceLock<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
     hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
-) -> &'tcx GlobalCtxt<'tcx> {
+) -> Result<&'tcx GlobalCtxt<'tcx>> {
+    let sess = &compiler.sess;
+
+    rustc_builtin_macros::cmdline_attrs::inject(
+        &mut krate,
+        &sess.psess,
+        &sess.opts.unstable_opts.crate_attr,
+    );
+
+    let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
+
+    // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
+    let crate_name = find_crate_name(sess, &pre_configured_attrs);
+    let crate_types = collect_crate_types(sess, &pre_configured_attrs);
+    let stable_crate_id = StableCrateId::new(
+        crate_name,
+        crate_types.contains(&CrateType::Executable),
+        sess.opts.cg.metadata.clone(),
+        sess.cfg_version,
+    );
+    let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
+    let dep_graph = setup_dep_graph(sess)?;
+
+    let cstore =
+        FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
+    let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
+
+    let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
+    let untracked =
+        Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions, stable_crate_ids };
+
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
-    let sess = &compiler.sess;
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
     let codegen_backend = &compiler.codegen_backend;
@@ -669,7 +698,7 @@ pub fn create_global_ctxt<'tcx>(
     let incremental = dep_graph.is_fully_enabled();
 
     sess.time("setup_global_ctxt", || {
-        gcx_cell.get_or_init(move || {
+        let qcx = gcx_cell.get_or_init(move || {
             TyCtxt::create_global_ctxt(
                 sess,
                 crate_types,
@@ -688,7 +717,23 @@ pub fn create_global_ctxt<'tcx>(
                 providers.hooks,
                 compiler.current_gcx.clone(),
             )
-        })
+        });
+
+        qcx.enter(|tcx| {
+            let feed = tcx.create_crate_num(stable_crate_id).unwrap();
+            assert_eq!(feed.key(), LOCAL_CRATE);
+            feed.crate_name(crate_name);
+
+            let feed = tcx.feed_unit_query();
+            feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
+                sess,
+                &pre_configured_attrs,
+                crate_name,
+            )));
+            feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
+            feed.output_filenames(Arc::new(outputs));
+        });
+        Ok(qcx)
     })
 }
 
@@ -924,12 +969,56 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     Ok(())
 }
 
+/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
+/// to write UI tests that actually test that compilation succeeds without reporting
+/// an error.
+fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
+    let Some((def_id, _)) = tcx.entry_fn(()) else { return };
+    for attr in tcx.get_attrs(def_id, sym::rustc_error) {
+        match attr.meta_item_list() {
+            // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
+            Some(list)
+                if list.iter().any(|list_item| {
+                    matches!(
+                        list_item.ident().map(|i| i.name),
+                        Some(sym::delayed_bug_from_inside_query)
+                    )
+                }) =>
+            {
+                tcx.ensure().trigger_delayed_bug(def_id);
+            }
+
+            // Bare `#[rustc_error]`.
+            None => {
+                tcx.dcx().emit_fatal(errors::RustcErrorFatal { span: tcx.def_span(def_id) });
+            }
+
+            // Some other attribute.
+            Some(_) => {
+                tcx.dcx().emit_warn(errors::RustcErrorUnexpectedAnnotation {
+                    span: tcx.def_span(def_id),
+                });
+            }
+        }
+    }
+}
+
 /// Runs the codegen backend, after which the AST and analysis can
 /// be discarded.
-pub fn start_codegen<'tcx>(
+pub(crate) fn start_codegen<'tcx>(
     codegen_backend: &dyn CodegenBackend,
     tcx: TyCtxt<'tcx>,
-) -> Box<dyn Any> {
+) -> Result<Box<dyn Any>> {
+    // Don't do code generation if there were any errors. Likewise if
+    // there were any delayed bugs, because codegen will likely cause
+    // more ICEs, obscuring the original problem.
+    if let Some(guar) = tcx.sess.dcx().has_errors_or_delayed_bugs() {
+        return Err(guar);
+    }
+
+    // Hook for UI tests.
+    check_for_rustc_errors_attr(tcx);
+
     info!("Pre-codegen\n{:?}", tcx.debug_stats());
 
     let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx);
@@ -952,7 +1041,7 @@ pub fn start_codegen<'tcx>(
         }
     }
 
-    codegen
+    Ok(codegen)
 }
 
 fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 1b9165342d4..cfd4304e893 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -1,26 +1,20 @@
-use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
+use crate::errors::FailedWritingFile;
 use crate::interface::{Compiler, Result};
-use crate::{errors, passes, util};
+use crate::{errors, passes};
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal};
-use rustc_hir::def_id::{StableCrateId, StableCrateIdMap, LOCAL_CRATE};
-use rustc_hir::definitions::Definitions;
-use rustc_incremental::setup_dep_graph;
-use rustc_metadata::creader::CStore;
+use rustc_data_structures::sync::{OnceLock, WorkerLocal};
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::{GlobalCtxt, TyCtxt};
 use rustc_serialize::opaque::FileEncodeResult;
-use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
-use rustc_session::cstore::Untracked;
-use rustc_session::output::{collect_crate_types, find_crate_name};
+use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::Session;
-use rustc_span::symbol::sym;
 use std::any::Any;
 use std::cell::{RefCell, RefMut};
 use std::sync::Arc;
@@ -106,133 +100,26 @@ impl<'tcx> Queries<'tcx> {
     }
 
     pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
-        self.parse.compute(|| {
-            passes::parse(&self.compiler.sess).map_err(|parse_error| parse_error.emit())
-        })
+        self.parse.compute(|| passes::parse(&self.compiler.sess))
     }
 
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
         self.gcx.compute(|| {
-            let sess = &self.compiler.sess;
-
-            let mut krate = self.parse()?.steal();
-
-            rustc_builtin_macros::cmdline_attrs::inject(
-                &mut krate,
-                &sess.psess,
-                &sess.opts.unstable_opts.crate_attr,
-            );
-
-            let pre_configured_attrs =
-                rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
-
-            // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
-            let crate_name = find_crate_name(sess, &pre_configured_attrs);
-            let crate_types = collect_crate_types(sess, &pre_configured_attrs);
-            let stable_crate_id = StableCrateId::new(
-                crate_name,
-                crate_types.contains(&CrateType::Executable),
-                sess.opts.cg.metadata.clone(),
-                sess.cfg_version,
-            );
-            let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
-            let dep_graph = setup_dep_graph(sess)?;
-
-            let cstore = FreezeLock::new(Box::new(CStore::new(
-                self.compiler.codegen_backend.metadata_loader(),
-            )) as _);
-            let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
-
-            let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
-            let untracked = Untracked {
-                cstore,
-                source_span: AppendOnlyIndexVec::new(),
-                definitions,
-                stable_crate_ids,
-            };
-
-            let qcx = passes::create_global_ctxt(
+            let krate = self.parse()?.steal();
+
+            passes::create_global_ctxt(
                 self.compiler,
-                crate_types,
-                stable_crate_id,
-                dep_graph,
-                untracked,
+                krate,
                 &self.gcx_cell,
                 &self.arena,
                 &self.hir_arena,
-            );
-
-            qcx.enter(|tcx| {
-                let feed = tcx.create_crate_num(stable_crate_id).unwrap();
-                assert_eq!(feed.key(), LOCAL_CRATE);
-                feed.crate_name(crate_name);
-
-                let feed = tcx.feed_unit_query();
-                feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
-                    sess,
-                    &pre_configured_attrs,
-                    crate_name,
-                )));
-                feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
-                feed.output_filenames(Arc::new(outputs));
-            });
-            Ok(qcx)
+            )
         })
     }
 
-    pub fn write_dep_info(&'tcx self) -> Result<()> {
-        self.global_ctxt()?.enter(|tcx| {
-            passes::write_dep_info(tcx);
-        });
-        Ok(())
-    }
-
-    /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
-    /// to write UI tests that actually test that compilation succeeds without reporting
-    /// an error.
-    fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
-        let Some((def_id, _)) = tcx.entry_fn(()) else { return };
-        for attr in tcx.get_attrs(def_id, sym::rustc_error) {
-            match attr.meta_item_list() {
-                // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
-                Some(list)
-                    if list.iter().any(|list_item| {
-                        matches!(
-                            list_item.ident().map(|i| i.name),
-                            Some(sym::delayed_bug_from_inside_query)
-                        )
-                    }) =>
-                {
-                    tcx.ensure().trigger_delayed_bug(def_id);
-                }
-
-                // Bare `#[rustc_error]`.
-                None => {
-                    tcx.dcx().emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) });
-                }
-
-                // Some other attribute.
-                Some(_) => {
-                    tcx.dcx()
-                        .emit_warn(RustcErrorUnexpectedAnnotation { span: tcx.def_span(def_id) });
-                }
-            }
-        }
-    }
-
     pub fn codegen_and_build_linker(&'tcx self) -> Result<Linker> {
         self.global_ctxt()?.enter(|tcx| {
-            // Don't do code generation if there were any errors. Likewise if
-            // there were any delayed bugs, because codegen will likely cause
-            // more ICEs, obscuring the original problem.
-            if let Some(guar) = self.compiler.sess.dcx().has_errors_or_delayed_bugs() {
-                return Err(guar);
-            }
-
-            // Hook for UI tests.
-            Self::check_for_rustc_errors_attr(tcx);
-
-            let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx);
+            let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?;
 
             Ok(Linker {
                 dep_graph: tcx.dep_graph.clone(),
diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr
index 7c421846535..9ac4c1c58f7 100644
--- a/tests/run-make/jobserver-error/cannot_open_fd.stderr
+++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr
@@ -4,3 +4,5 @@ warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--
 
 error: no input filename given
 
+error: aborting due to 1 previous error
+
diff --git a/tests/run-make/no-input-file/rmake.rs b/tests/run-make/no-input-file/rmake.rs
index fc558b22fb4..d76a8f9e7c1 100644
--- a/tests/run-make/no-input-file/rmake.rs
+++ b/tests/run-make/no-input-file/rmake.rs
@@ -1,9 +1,9 @@
 use run_make_support::rustc;
 
 fn main() {
-    rustc()
-        .print("crate-name")
-        .run_fail()
-        .assert_exit_code(1)
-        .assert_stderr_equals("error: no input filename given");
+    rustc().print("crate-name").run_fail().assert_exit_code(1).assert_stderr_equals(
+        "error: no input filename given
+
+error: aborting due to 1 previous error",
+    );
 }
diff --git a/tests/ui/deployment-target/invalid-target.stderr b/tests/ui/deployment-target/invalid-target.stderr
index eb4ac131c40..0ab548f339b 100644
--- a/tests/ui/deployment-target/invalid-target.stderr
+++ b/tests/ui/deployment-target/invalid-target.stderr
@@ -1,2 +1,4 @@
 error: only Apple targets currently support deployment version info
 
+error: aborting due to 1 previous error
+