about summary refs log tree commit diff
path: root/compiler/rustc_interface/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_interface/src')
-rw-r--r--compiler/rustc_interface/src/interface.rs61
-rw-r--r--compiler/rustc_interface/src/lib.rs6
-rw-r--r--compiler/rustc_interface/src/passes.rs151
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs163
-rw-r--r--compiler/rustc_interface/src/tests.rs10
-rw-r--r--compiler/rustc_interface/src/util.rs8
7 files changed, 153 insertions, 248 deletions
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3920d3077d3..1456255ea14 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -5,9 +5,9 @@ use std::sync::Arc;
 use rustc_ast::{LitKind, MetaItemKind, token};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::jobserver;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::{defer, jobserver};
 use rustc_errors::registry::Registry;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
 use rustc_lint::LintStore;
@@ -22,9 +22,8 @@ use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileN
 use rustc_session::filesearch::{self, sysroot_candidates};
 use rustc_session::parse::ParseSess;
 use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint};
-use rustc_span::FileName;
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
-use rustc_span::symbol::sym;
+use rustc_span::{FileName, sym};
 use tracing::trace;
 
 use crate::util;
@@ -371,7 +370,6 @@ pub(crate) fn initialize_checked_jobserver(early_dcx: &EarlyDiagCtxt) {
 
 // JUSTIFICATION: before session exists, only config
 #[allow(rustc::bad_opt_access)]
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
     trace!("run_compiler");
 
@@ -425,7 +423,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.opts.unstable_opts.translate_directionality_markers,
             ) {
                 Ok(bundle) => bundle,
-                Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
+                Err(e) => {
+                    // We can't translate anything if we failed to load translations
+                    #[allow(rustc::untranslatable_diagnostic)]
+                    early_dcx.early_fatal(format!("failed to load fluent bundle: {e}"))
+                }
             };
 
             let mut locale_resources = config.locale_resources;
@@ -441,7 +443,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                     temps_dir,
                 },
                 bundle,
-                config.registry.clone(),
+                config.registry,
                 locale_resources,
                 config.lint_caps,
                 target,
@@ -479,7 +481,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
             if let Some(register_lints) = config.register_lints.as_deref() {
                 register_lints(&sess, &mut lint_store);
-                sess.registered_lints = true;
             }
             sess.lint_store = Some(Lrc::new(lint_store));
 
@@ -492,32 +493,34 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             // There are two paths out of `f`.
             // - Normal exit.
-            // - Panic, e.g. triggered by `abort_if_errors`.
+            // - Panic, e.g. triggered by `abort_if_errors` or a fatal error.
             //
             // We must run `finish_diagnostics` in both cases.
-            let res = {
-                // If `f` panics, `finish_diagnostics` will run during
-                // unwinding because of the `defer`.
-                let sess_abort_guard = defer(|| {
-                    compiler.sess.finish_diagnostics(&config.registry);
-                });
-
-                let res = f(&compiler);
-
-                // If `f` doesn't panic, `finish_diagnostics` will run
-                // normally when `sess_abort_guard` is dropped.
-                drop(sess_abort_guard);
-
-                // 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.
+            let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&compiler)));
+
+            compiler.sess.finish_diagnostics();
+
+            // 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.
+            if res.is_ok() {
                 compiler.sess.dcx().abort_if_errors();
+            }
+
+            // Also make sure to flush delayed bugs as if we panicked, the
+            // bugs would be flushed by the Drop impl of DiagCtxt while
+            // unwinding, which would result in an abort with
+            // "panic in a destructor during cleanup".
+            compiler.sess.dcx().flush_delayed();
 
-                res
+            let res = match res {
+                Ok(res) => res,
+                // Resume unwinding if a panic happened.
+                Err(err) => std::panic::resume_unwind(err),
             };
 
             let prof = compiler.sess.prof.clone();
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 1c4dda2a436..a2a29612e48 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -8,7 +8,7 @@
 // tidy-alphabetical-end
 
 mod callbacks;
-mod errors;
+pub mod errors;
 pub mod interface;
 pub mod passes;
 mod proc_macro_decls;
@@ -17,8 +17,8 @@ pub mod util;
 
 pub use callbacks::setup_callbacks;
 pub use interface::{Config, run_compiler};
-pub use passes::DEFAULT_QUERY_PROVIDERS;
-pub use queries::{Linker, Queries};
+pub use passes::{DEFAULT_QUERY_PROVIDERS, create_and_enter_global_ctxt, parse};
+pub use queries::Linker;
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index d42915f4110..aff66e48fbb 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -19,7 +19,7 @@ use rustc_incremental::setup_dep_graph;
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
-use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
+use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_parse::{
     new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
@@ -32,16 +32,15 @@ use rustc_session::cstore::Untracked;
 use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
-use rustc_span::symbol::{Symbol, sym};
-use rustc_span::{FileName, SourceFileHash, SourceFileHashAlgorithm};
+use rustc_span::{ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Symbol, sym};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 use tracing::{info, instrument};
 
-use crate::interface::{Compiler, Result};
+use crate::interface::Compiler;
 use crate::{errors, proc_macro_decls, util};
 
-pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
+pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
     let krate = sess
         .time("parse_crate", || {
             let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
@@ -52,13 +51,16 @@ pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
             });
             parser.parse_crate_mod()
         })
-        .map_err(|parse_error| parse_error.emit())?;
+        .unwrap_or_else(|parse_error| {
+            let guar: ErrorGuaranteed = parse_error.emit();
+            guar.raise_fatal();
+        });
 
     if sess.opts.unstable_opts.input_stats {
         input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
     }
 
-    Ok(krate)
+    krate
 }
 
 fn pre_expansion_lint<'a>(
@@ -73,6 +75,7 @@ fn pre_expansion_lint<'a>(
         || {
             rustc_lint::check_ast_node(
                 sess,
+                None,
                 features,
                 true,
                 lint_store,
@@ -307,6 +310,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let lint_store = unerased_lint_store(tcx.sess);
     rustc_lint::check_ast_node(
         sess,
+        Some(tcx),
         tcx.features(),
         false,
         lint_store,
@@ -706,13 +710,11 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     *providers
 });
 
-pub(crate) fn create_global_ctxt<'tcx>(
-    compiler: &'tcx Compiler,
+pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
+    compiler: &Compiler,
     mut krate: rustc_ast::Crate,
-    gcx_cell: &'tcx OnceLock<GlobalCtxt<'tcx>>,
-    arena: &'tcx WorkerLocal<Arena<'tcx>>,
-    hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
-) -> Result<&'tcx GlobalCtxt<'tcx>> {
+    f: F,
+) -> T {
     let sess = &compiler.sess;
 
     rustc_builtin_macros::cmdline_attrs::inject(
@@ -733,7 +735,7 @@ pub(crate) fn create_global_ctxt<'tcx>(
         sess.cfg_version,
     );
     let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
-    let dep_graph = setup_dep_graph(sess)?;
+    let dep_graph = setup_dep_graph(sess);
 
     let cstore =
         FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
@@ -760,44 +762,63 @@ pub(crate) fn create_global_ctxt<'tcx>(
 
     let incremental = dep_graph.is_fully_enabled();
 
-    sess.time("setup_global_ctxt", || {
-        let qcx = gcx_cell.get_or_init(move || {
-            TyCtxt::create_global_ctxt(
-                sess,
-                crate_types,
-                stable_crate_id,
-                arena,
-                hir_arena,
-                untracked,
-                dep_graph,
-                rustc_query_impl::query_callbacks(arena),
-                rustc_query_impl::query_system(
-                    providers.queries,
-                    providers.extern_queries,
-                    query_result_on_disk_cache,
-                    incremental,
-                ),
-                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 gcx_cell = OnceLock::new();
+    let arena = WorkerLocal::new(|_| Arena::default());
+    let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default());
+
+    // This closure is necessary to force rustc to perform the correct lifetime
+    // subtyping for GlobalCtxt::enter to be allowed.
+    let inner: Box<
+        dyn for<'tcx> FnOnce(
+            &'tcx Session,
+            CurrentGcx,
+            &'tcx OnceLock<GlobalCtxt<'tcx>>,
+            &'tcx WorkerLocal<Arena<'tcx>>,
+            &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
+            F,
+        ) -> T,
+    > = Box::new(move |sess, current_gcx, gcx_cell, arena, hir_arena, f| {
+        TyCtxt::create_global_ctxt(
+            gcx_cell,
+            sess,
+            crate_types,
+            stable_crate_id,
+            arena,
+            hir_arena,
+            untracked,
+            dep_graph,
+            rustc_query_impl::query_callbacks(arena),
+            rustc_query_impl::query_system(
+                providers.queries,
+                providers.extern_queries,
+                query_result_on_disk_cache,
+                incremental,
+            ),
+            providers.hooks,
+            current_gcx,
+            |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(
+                    tcx.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));
+
+                let res = f(tcx);
+                // FIXME maybe run finish even when a fatal error occured? or at least tcx.alloc_self_profile_query_strings()?
+                tcx.finish();
+                res
+            },
+        )
+    });
 
-            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)
-    })
+    inner(&compiler.sess, compiler.current_gcx.clone(), &gcx_cell, &arena, &hir_arena, f)
 }
 
 /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
@@ -876,7 +897,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 || tcx.hir().body_const_context(def_id).is_some()
             {
                 tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
-                tcx.ensure().unused_generic_params(ty::InstanceKind::Item(def_id.to_def_id()));
             }
         }
     });
@@ -895,8 +915,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
     // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
     // in MIR optimizations that may only be reachable through codegen, or other codepaths
-    // that requires the optimized/ctfe MIR, such as polymorphization, coroutine bodies,
-    // or evaluating consts.
+    // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
     if tcx.sess.opts.unstable_opts.validate_mir {
         sess.time("ensuring_final_MIR_is_computable", || {
             tcx.hir().par_body_owners(|def_id| {
@@ -908,7 +927,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
 
 /// Runs the type-checking, region checking and other miscellaneous analysis
 /// passes on the crate.
-fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
+fn analysis(tcx: TyCtxt<'_>, (): ()) {
     run_required_analyses(tcx);
 
     let sess = tcx.sess;
@@ -922,7 +941,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     // But we exclude lint errors from this, because lint errors are typically
     // less serious and we're more likely to want to continue (#87337).
     if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() {
-        return Err(guar);
+        guar.raise_fatal();
     }
 
     sess.time("misc_checking_3", || {
@@ -1050,8 +1069,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             })
         }
     }
-
-    Ok(())
 }
 
 /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
@@ -1093,12 +1110,12 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
 pub(crate) fn start_codegen<'tcx>(
     codegen_backend: &dyn CodegenBackend,
     tcx: TyCtxt<'tcx>,
-) -> Result<Box<dyn Any>> {
+) -> 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);
+        guar.raise_fatal();
     }
 
     // Hook for UI tests.
@@ -1126,7 +1143,19 @@ pub(crate) fn start_codegen<'tcx>(
         }
     }
 
-    Ok(codegen)
+    // This must run after monomorphization so that all generic types
+    // have been instantiated.
+    if tcx.sess.opts.unstable_opts.print_type_sizes {
+        tcx.sess.code_stats.print_type_sizes();
+    }
+
+    if tcx.sess.opts.unstable_opts.print_vtable_sizes {
+        let crate_name = tcx.crate_name(LOCAL_CRATE);
+
+        tcx.sess.code_stats.print_vtable_sizes(crate_name);
+    }
+
+    codegen
 }
 
 fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 2c8014d8b3a..82593dbc2b7 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -2,7 +2,7 @@ use rustc_ast::attr;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
+use rustc_span::sym;
 
 fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
     let mut decls = None;
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index cd3a2fb7049..c8914c9be9c 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -1,119 +1,18 @@
 use std::any::Any;
-use std::cell::{RefCell, RefMut};
 use std::sync::Arc;
 
-use rustc_ast as ast;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
-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_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 
 use crate::errors::FailedWritingFile;
-use crate::interface::{Compiler, Result};
 use crate::passes;
 
-/// Represent the result of a query.
-///
-/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method.
-///
-/// [`steal`]: Steal::steal
-/// [`compute`]: Self::compute
-pub struct Query<T> {
-    /// `None` means no value has been computed yet.
-    result: RefCell<Option<Result<Steal<T>>>>,
-}
-
-impl<T> Query<T> {
-    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> {
-        RefMut::filter_map(
-            self.result.borrow_mut(),
-            |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> {
-                r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok()
-            },
-        )
-        .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err())
-        .map(QueryResult)
-    }
-}
-
-pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>);
-
-impl<'a, T> std::ops::Deref for QueryResult<'a, T> {
-    type Target = RefMut<'a, Steal<T>>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
-impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> {
-    pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
-        (*self.0).borrow().enter(f)
-    }
-}
-
-pub struct Queries<'tcx> {
-    compiler: &'tcx Compiler,
-    gcx_cell: OnceLock<GlobalCtxt<'tcx>>,
-
-    arena: WorkerLocal<Arena<'tcx>>,
-    hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
-
-    parse: Query<ast::Crate>,
-    // This just points to what's in `gcx_cell`.
-    gcx: Query<&'tcx GlobalCtxt<'tcx>>,
-}
-
-impl<'tcx> Queries<'tcx> {
-    pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
-        Queries {
-            compiler,
-            gcx_cell: OnceLock::new(),
-            arena: WorkerLocal::new(|_| Arena::default()),
-            hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
-            parse: Query { result: RefCell::new(None) },
-            gcx: Query { result: RefCell::new(None) },
-        }
-    }
-
-    pub fn finish(&'tcx self) {
-        if let Some(gcx) = self.gcx_cell.get() {
-            gcx.finish();
-        }
-    }
-
-    pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
-        self.parse.compute(|| passes::parse(&self.compiler.sess))
-    }
-
-    pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>>> {
-        self.gcx.compute(|| {
-            let krate = self.parse()?.steal();
-
-            passes::create_global_ctxt(
-                self.compiler,
-                krate,
-                &self.gcx_cell,
-                &self.arena,
-                &self.hir_arena,
-            )
-        })
-    }
-}
-
 pub struct Linker {
     dep_graph: DepGraph,
     output_filenames: Arc<OutputFilenames>,
@@ -126,22 +25,10 @@ impl Linker {
     pub fn codegen_and_build_linker(
         tcx: TyCtxt<'_>,
         codegen_backend: &dyn CodegenBackend,
-    ) -> Result<Linker> {
-        let ongoing_codegen = passes::start_codegen(codegen_backend, tcx)?;
-
-        // This must run after monomorphization so that all generic types
-        // have been instantiated.
-        if tcx.sess.opts.unstable_opts.print_type_sizes {
-            tcx.sess.code_stats.print_type_sizes();
-        }
+    ) -> Linker {
+        let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
 
-        if tcx.sess.opts.unstable_opts.print_vtable_sizes {
-            let crate_name = tcx.crate_name(LOCAL_CRATE);
-
-            tcx.sess.code_stats.print_vtable_sizes(crate_name);
-        }
-
-        Ok(Linker {
+        Linker {
             dep_graph: tcx.dep_graph.clone(),
             output_filenames: Arc::clone(tcx.output_filenames(())),
             crate_hash: if tcx.needs_crate_hash() {
@@ -150,16 +37,17 @@ impl Linker {
                 None
             },
             ongoing_codegen,
-        })
+        }
     }
 
-    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> {
-        let (codegen_results, work_products) =
-            codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames);
+    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
+        let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || {
+            codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)
+        });
 
-        if let Some(guar) = sess.dcx().has_errors() {
-            return Err(guar);
-        }
+        sess.dcx().abort_if_errors();
+
+        let _timer = sess.timer("link");
 
         sess.time("serialize_work_products", || {
             rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
@@ -178,7 +66,7 @@ impl Linker {
             .keys()
             .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
         {
-            return Ok(());
+            return;
         }
 
         if sess.opts.unstable_opts.no_link {
@@ -189,32 +77,13 @@ impl Linker {
                 &codegen_results,
                 &*self.output_filenames,
             )
-            .map_err(|error| {
+            .unwrap_or_else(|error| {
                 sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
-            })?;
-            return Ok(());
+            });
+            return;
         }
 
         let _timer = sess.prof.verbose_generic_activity("link_crate");
         codegen_backend.link(sess, codegen_results, &self.output_filenames)
     }
 }
-
-impl Compiler {
-    pub fn enter<F, T>(&self, f: F) -> T
-    where
-        F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T,
-    {
-        // Must declare `_timer` first so that it is dropped after `queries`.
-        let _timer;
-        let queries = Queries::new(self);
-        let ret = f(&queries);
-
-        // The timer's lifetime spans the dropping of `queries`, which contains
-        // the global context.
-        _timer = self.sess.timer("free_global_ctxt");
-        queries.finish();
-
-        ret
-    }
-}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 3c4d9c2e928..9ad69039914 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -23,8 +23,7 @@ use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, filesearch, getopts};
 use rustc_span::edition::{DEFAULT_EDITION, Edition};
 use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
-use rustc_span::symbol::sym;
-use rustc_span::{FileName, SourceFileHashAlgorithm};
+use rustc_span::{FileName, SourceFileHashAlgorithm, sym};
 use rustc_target::spec::{
     CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
     RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi,
@@ -767,7 +766,11 @@ fn test_unstable_options_tracking_hash() {
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
-    tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true });
+    tracked!(coverage_options, CoverageOptions {
+        level: CoverageLevel::Mcdc,
+        no_mir_spans: true,
+        discard_all_spans_in_codegen: true
+    });
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
@@ -832,6 +835,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(precise_enum_drop_elaboration, false);
     tracked!(profile_sample_use, Some(PathBuf::from("abc")));
     tracked!(profiler_runtime, "abc".to_string());
+    tracked!(reg_struct_return, true);
     tracked!(regparm, Some(3));
     tracked!(relax_elf_relocations, Some(true));
     tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index d3213b1263c..984b8104f53 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -18,7 +18,7 @@ use rustc_session::{EarlyDiagCtxt, Session, filesearch};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMapInputs;
-use rustc_span::symbol::sym;
+use rustc_span::sym;
 use rustc_target::spec::Target;
 use tracing::info;
 
@@ -35,10 +35,10 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
 pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
     let tf = sym::target_feature;
 
-    let unstable_target_features = codegen_backend.target_features(sess, true);
+    let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
     sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
 
-    let target_features = codegen_backend.target_features(sess, false);
+    let target_features = codegen_backend.target_features_cfg(sess, false);
     sess.target_features.extend(target_features.iter().cloned());
 
     cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
@@ -453,7 +453,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
         .opts
         .crate_name
         .clone()
-        .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()));
+        .or_else(|| rustc_attr_parsing::find_crate_name(attrs).map(|n| n.to_string()));
 
     match sess.io.output_file {
         None => {