about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs82
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs34
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs34
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs353
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl119
-rw-r--r--compiler/rustc_error_messages/src/lib.rs16
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs19
-rw-r--r--compiler/rustc_hir/src/def.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs3
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/late.rs61
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs36
-rw-r--r--compiler/rustc_resolve/src/lib.rs18
-rw-r--r--compiler/rustc_resolve/src/macros.rs9
23 files changed, 669 insertions, 207 deletions
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 85306d7184d..54c83fb7604 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -205,13 +205,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         let static_def_id = self
                             .resolver
                             .get_partial_res(sym.id)
-                            .filter(|res| res.unresolved_segments() == 0)
-                            .and_then(|res| {
-                                if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
-                                    Some(def_id)
-                                } else {
-                                    None
-                                }
+                            .and_then(|res| res.full_res())
+                            .and_then(|res| match res {
+                                Res::Def(DefKind::Static(_), def_id) => Some(def_id),
+                                _ => None,
                             });
 
                         if let Some(def_id) = static_def_id {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 46886c518af..c55b4906302 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1044,9 +1044,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         if let ExprKind::Path(qself, path) = &expr.kind {
             // Does the path resolve to something disallowed in a tuple struct/variant pattern?
             if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
-                if partial_res.unresolved_segments() == 0
-                    && !partial_res.base_res().expected_in_tuple_struct_pat()
-                {
+                if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() {
                     return None;
                 }
             }
@@ -1066,9 +1064,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         if let ExprKind::Path(qself, path) = &expr.kind {
             // Does the path resolve to something disallowed in a unit struct/variant pattern?
             if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
-                if partial_res.unresolved_segments() == 0
-                    && !partial_res.base_res().expected_in_unit_struct_pat()
-                {
+                if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() {
                     return None;
                 }
             }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 56d71aaa7d3..687d810ed4e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -947,7 +947,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 AssocItemKind::MacCall(..) => unimplemented!(),
             },
-            trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
+            trait_item_def_id: self
+                .resolver
+                .get_partial_res(i.id)
+                .map(|r| r.expect_full_res().def_id()),
         }
     }
 
@@ -1349,9 +1352,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 match self
                     .resolver
                     .get_partial_res(bound_pred.bounded_ty.id)
-                    .map(|d| (d.base_res(), d.unresolved_segments()))
+                    .and_then(|r| r.full_res())
                 {
-                    Some((Res::Def(DefKind::TyParam, def_id), 0))
+                    Some(Res::Def(DefKind::TyParam, def_id))
                         if bound_pred.bound_generic_params.is_empty() =>
                     {
                         generics
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8281164ab12..ce5893efa92 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -175,12 +175,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
                 return None;
             }
 
-            let partial_res = self.partial_res_map.get(&expr.id)?;
-            if partial_res.unresolved_segments() != 0 {
-                return None;
-            }
-
-            if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() {
+            if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? {
                 // We only support cross-crate argument rewriting. Uses
                 // within the same crate should be updated to use the new
                 // const generics style.
@@ -753,12 +748,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
-        self.resolver.get_partial_res(id).map_or(Res::Err, |pr| {
-            if pr.unresolved_segments() != 0 {
-                panic!("path not fully resolved: {:?}", pr);
-            }
-            pr.base_res()
-        })
+        self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
     }
 
     fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
@@ -1138,8 +1128,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // type and value namespaces. If we resolved the path in the value namespace, we
                     // transform it into a generic const argument.
                     TyKind::Path(ref qself, ref path) => {
-                        if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
-                            let res = partial_res.base_res();
+                        if let Some(res) = self
+                            .resolver
+                            .get_partial_res(ty.id)
+                            .and_then(|partial_res| partial_res.full_res())
+                        {
                             if !res.matches_ns(Namespace::TypeNS) {
                                 debug!(
                                     "lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -1206,8 +1199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // by `ty_path`.
         if qself.is_none()
             && let Some(partial_res) = self.resolver.get_partial_res(t.id)
-            && partial_res.unresolved_segments() == 0
-            && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+            && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
         {
             let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
                 let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 1ea76fdbfcb..1af1633b524 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -239,7 +239,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ident: Ident,
         lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
     ) -> hir::PatKind<'hir> {
-        match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
+        match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
             // `None` can occur in body-less function signatures
             res @ (None | Some(Res::Local(_))) => {
                 let canonical_id = match res {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 6bb1bb9eace..888776cccac 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -29,11 +29,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
+        let base_res = partial_res.base_res();
+        let unresolved_segments = partial_res.unresolved_segments();
 
         let path_span_lo = p.span.shrink_to_lo();
-        let proj_start = p.segments.len() - partial_res.unresolved_segments();
+        let proj_start = p.segments.len() - unresolved_segments;
         let path = self.arena.alloc(hir::Path {
-            res: self.lower_res(partial_res.base_res()),
+            res: self.lower_res(base_res),
             segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
                 |(i, segment)| {
                     let param_mode = match (qself_position, param_mode) {
@@ -46,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         _ => param_mode,
                     };
 
-                    let parenthesized_generic_args = match partial_res.base_res() {
+                    let parenthesized_generic_args = match base_res {
                         // `a::b::Trait(Args)`
                         Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
                             ParenthesizedGenericArgs::Ok
@@ -83,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // Simple case, either no projections, or only fully-qualified.
         // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
-        if partial_res.unresolved_segments() == 0 {
+        if unresolved_segments == 0 {
             return hir::QPath::Resolved(qself, path);
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 9a0c379b4e4..95e72184ff0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -31,7 +31,9 @@ use super::command::Command;
 use super::linker::{self, Linker};
 use super::metadata::{create_rmeta_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
-use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
+use crate::{
+    errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+};
 
 use cc::windows_registry;
 use regex::Regex;
@@ -93,7 +95,7 @@ pub fn link_binary<'a>(
             let tmpdir = TempFileBuilder::new()
                 .prefix("rustc")
                 .tempdir()
-                .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+                .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
             let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
             let out_filename = out_filename(
                 sess,
@@ -208,7 +210,7 @@ pub fn link_binary<'a>(
 pub fn each_linked_rlib(
     info: &CrateInfo,
     f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
     let mut fmts = None;
     for (ty, list) in info.dependency_formats.iter() {
@@ -224,26 +226,23 @@ pub fn each_linked_rlib(
         }
     }
     let Some(fmts) = fmts else {
-        return Err("could not find formats for rlibs".to_string());
+        return Err(errors::LinkRlibError::MissingFormat);
     };
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
             Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
             Some(_) => {}
-            None => return Err("could not find formats for rlibs".to_string()),
+            None => return Err(errors::LinkRlibError::MissingFormat),
         }
-        let name = info.crate_name[&cnum];
+        let crate_name = info.crate_name[&cnum];
         let used_crate_source = &info.used_crate_source[&cnum];
         if let Some((path, _)) = &used_crate_source.rlib {
             f(cnum, &path);
         } else {
             if used_crate_source.rmeta.is_some() {
-                return Err(format!(
-                    "could not find rlib for: `{}`, found rmeta (metadata) file",
-                    name
-                ));
+                return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
             } else {
-                return Err(format!("could not find rlib for: `{}`", name));
+                return Err(errors::LinkRlibError::NotFound { crate_name });
             }
         }
     }
@@ -340,10 +339,7 @@ fn link_rlib<'a>(
                 // -whole-archive and it isn't clear how we can currently handle such a
                 // situation correctly.
                 // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
-                sess.err(
-                    "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
-                        with each other when generating rlibs",
-                );
+                sess.emit_err(errors::IncompatibleLinkingModifiers);
             }
             NativeLibKind::Static { bundle: None | Some(true), .. } => {}
             NativeLibKind::Static { bundle: Some(false), .. }
@@ -365,12 +361,8 @@ fn link_rlib<'a>(
                 ));
                 continue;
             }
-            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
-                sess.fatal(&format!(
-                    "failed to add native library {}: {}",
-                    location.to_string_lossy(),
-                    e
-                ));
+            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
+                sess.emit_fatal(errors::AddNativeLibrary { library_path: location, error });
             });
         }
     }
@@ -385,8 +377,8 @@ fn link_rlib<'a>(
             tmpdir.as_ref(),
         );
 
-        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
-            sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
+        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
+            sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
     }
 
@@ -451,14 +443,11 @@ fn collate_raw_dylibs(
                     // FIXME: when we add support for ordinals, figure out if we need to do anything
                     // if we have two DllImport values with the same name but different ordinals.
                     if import.calling_convention != old_import.calling_convention {
-                        sess.span_err(
-                            import.span,
-                            &format!(
-                                "multiple declarations of external function `{}` from \
-                                 library `{}` have different calling conventions",
-                                import.name, name,
-                            ),
-                        );
+                        sess.emit_err(errors::MultipleExternalFuncDecl {
+                            span: import.span,
+                            function: import.name,
+                            library_name: &name,
+                        });
                     }
                 }
             }
@@ -560,7 +549,7 @@ fn link_staticlib<'a>(
         all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
     });
     if let Err(e) = res {
-        sess.fatal(&e);
+        sess.emit_fatal(e);
     }
 
     ab.build(out_filename);
@@ -673,9 +662,7 @@ fn link_dwarf_object<'a>(
     }) {
         Ok(()) => {}
         Err(e) => {
-            sess.struct_err("linking dwarf objects with thorin failed")
-                .note(&format!("{:?}", e))
-                .emit();
+            sess.emit_err(errors::ThorinErrorWrapper(e));
             sess.abort_if_errors();
         }
     }
@@ -879,23 +866,14 @@ fn link_natively<'a>(
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_string(&output);
-                let mut err = sess.struct_err(&format!(
-                    "linking with `{}` failed: {}",
-                    linker_path.display(),
-                    prog.status
-                ));
-                err.note(&format!("{:?}", &cmd)).note(&escaped_output);
-                if escaped_output.contains("undefined reference to") {
-                    err.help(
-                        "some `extern` functions couldn't be found; some native libraries may \
-                         need to be installed or have their path specified",
-                    );
-                    err.note("use the `-l` flag to specify native libraries to link");
-                    err.note("use the `cargo:rustc-link-lib` directive to specify the native \
-                              libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
-                }
-                err.emit();
-
+                // FIXME: Add UI tests for this error.
+                let err = errors::LinkingFailed {
+                    linker_path: &linker_path,
+                    exit_status: prog.status,
+                    command: &cmd,
+                    escaped_output: &escaped_output,
+                };
+                sess.diagnostic().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index c71d332475a..bad22ccb1fe 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,5 +1,6 @@
 use super::command::Command;
 use super::symbol_export;
+use crate::errors;
 use rustc_span::symbol::sym;
 
 use std::ffi::{OsStr, OsString};
@@ -434,11 +435,11 @@ impl<'a> Linker for GccLinker<'a> {
                 // FIXME(81490): ld64 doesn't support these flags but macOS 11
                 // has -needed-l{} / -needed_library {}
                 // but we have no way to detect that here.
-                self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+                self.sess.emit_warning(errors::Ld64UnimplementedModifier);
             } else if self.is_gnu && !self.sess.target.is_like_windows {
                 self.linker_arg("--no-as-needed");
             } else {
-                self.sess.warn("`as-needed` modifier not supported for current linker");
+                self.sess.emit_warning(errors::LinkerUnsupportedModifier);
             }
         }
         self.hint_dynamic();
@@ -492,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> {
             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
             // flag but we have no way to detect that here.
             // self.cmd.arg("-needed_framework").arg(framework);
-            self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+            self.sess.emit_warning(errors::Ld64UnimplementedModifier);
         }
         self.cmd.arg("-framework").arg(framework);
     }
@@ -665,8 +666,8 @@ impl<'a> Linker for GccLinker<'a> {
                     writeln!(f, "_{}", sym)?;
                 }
             };
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+            if let Err(error) = res {
+                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else if is_windows {
             let res: io::Result<()> = try {
@@ -680,8 +681,8 @@ impl<'a> Linker for GccLinker<'a> {
                     writeln!(f, "  {}", symbol)?;
                 }
             };
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write list.def file: {}", e));
+            if let Err(error) = res {
+                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else {
             // Write an LD version script
@@ -697,8 +698,8 @@ impl<'a> Linker for GccLinker<'a> {
                 }
                 writeln!(f, "\n  local:\n    *;\n}};")?;
             };
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write version script: {}", e));
+            if let Err(error) = res {
+                self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
             }
         }
 
@@ -915,9 +916,8 @@ impl<'a> Linker for MsvcLinker<'a> {
                                     self.cmd.arg(arg);
                                 }
                             }
-                            Err(err) => {
-                                self.sess
-                                    .warn(&format!("error enumerating natvis directory: {}", err));
+                            Err(error) => {
+                                self.sess.emit_warning(errors::NoNatvisDirectory { error });
                             }
                         }
                     }
@@ -971,8 +971,8 @@ impl<'a> Linker for MsvcLinker<'a> {
                 writeln!(f, "  {}", symbol)?;
             }
         };
-        if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+        if let Err(error) = res {
+            self.sess.emit_fatal(errors::LibDefWriteFailure { error });
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
@@ -1435,7 +1435,7 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
         // ToDo, not implemented, copy from GCC
-        self.sess.warn("exporting symbols not implemented yet for L4Bender");
+        self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
         return;
     }
 
@@ -1727,8 +1727,8 @@ impl<'a> Linker for BpfLinker<'a> {
                 writeln!(f, "{}", sym)?;
             }
         };
-        if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write symbols file: {}", e));
+        if let Err(error) = res {
+            self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
         } else {
             self.cmd.arg("--export-symbols").arg(&path);
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 6188094bbbd..1f577e9f352 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -2,11 +2,11 @@ use super::link::{self, ensure_removed};
 use super::lto::{self, SerializedModule};
 use super::symbol_export::symbol_name_for_instance_in_crate;
 
+use crate::errors;
+use crate::traits::*;
 use crate::{
     CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
 };
-
-use crate::traits::*;
 use jobserver::{Acquired, Client};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::memmap::Mmap;
@@ -530,7 +530,7 @@ fn produce_final_output_artifacts(
     // Produce final compile outputs.
     let copy_gracefully = |from: &Path, to: &Path| {
         if let Err(e) = fs::copy(from, to) {
-            sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
+            sess.emit_err(errors::CopyPath::new(from, to, e));
         }
     };
 
@@ -546,7 +546,7 @@ fn produce_final_output_artifacts(
                 ensure_removed(sess.diagnostic(), &path);
             }
         } else {
-            let ext = crate_output
+            let extension = crate_output
                 .temp_path(output_type, None)
                 .extension()
                 .unwrap()
@@ -557,19 +557,11 @@ fn produce_final_output_artifacts(
             if crate_output.outputs.contains_key(&output_type) {
                 // 2) Multiple codegen units, with `--emit foo=some_name`.  We have
                 //    no good solution for this case, so warn the user.
-                sess.warn(&format!(
-                    "ignoring emit path because multiple .{} files \
-                                    were produced",
-                    ext
-                ));
+                sess.emit_warning(errors::IgnoringEmitPath { extension });
             } else if crate_output.single_output_file.is_some() {
                 // 3) Multiple codegen units, with `-o some_name`.  We have
                 //    no good solution for this case, so warn the user.
-                sess.warn(&format!(
-                    "ignoring -o because multiple .{} files \
-                                    were produced",
-                    ext
-                ));
+                sess.emit_warning(errors::IgnoringOutput { extension });
             } else {
                 // 4) Multiple codegen units, but no explicit name.  We
                 //    just leave the `foo.0.x` files in place.
@@ -880,14 +872,12 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
         );
         match link_or_copy(&source_file, &output_path) {
             Ok(_) => Some(output_path),
-            Err(err) => {
-                let diag_handler = cgcx.create_diag_handler();
-                diag_handler.err(&format!(
-                    "unable to copy {} to {}: {}",
-                    source_file.display(),
-                    output_path.display(),
-                    err
-                ));
+            Err(error) => {
+                cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
+                    source_file,
+                    output_path,
+                    error,
+                });
                 None
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
new file mode 100644
index 00000000000..0ffe8872022
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -0,0 +1,353 @@
+//! Errors emitted by codegen_ssa
+
+use crate::back::command::Command;
+use rustc_errors::{
+    fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    IntoDiagnosticArg,
+};
+use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
+use std::io::Error;
+use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::lib_def_write_failure)]
+pub struct LibDefWriteFailure {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::version_script_write_failure)]
+pub struct VersionScriptWriteFailure {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::symbol_file_write_failure)]
+pub struct SymbolFileWriteFailure {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::ld64_unimplemented_modifier)]
+pub struct Ld64UnimplementedModifier;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::linker_unsupported_modifier)]
+pub struct LinkerUnsupportedModifier;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
+pub struct L4BenderExportingSymbolsUnimplemented;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::no_natvis_directory)]
+pub struct NoNatvisDirectory {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::copy_path_buf)]
+pub struct CopyPathBuf {
+    pub source_file: PathBuf,
+    pub output_path: PathBuf,
+    pub error: Error,
+}
+
+// Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::copy_path)]
+pub struct CopyPath<'a> {
+    from: DebugArgPath<'a>,
+    to: DebugArgPath<'a>,
+    error: Error,
+}
+
+impl<'a> CopyPath<'a> {
+    pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
+        CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
+    }
+}
+
+struct DebugArgPath<'a>(pub &'a Path);
+
+impl IntoDiagnosticArg for DebugArgPath<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::ignoring_emit_path)]
+pub struct IgnoringEmitPath {
+    pub extension: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::ignoring_output)]
+pub struct IgnoringOutput {
+    pub extension: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::create_temp_dir)]
+pub struct CreateTempDir {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::incompatible_linking_modifiers)]
+pub struct IncompatibleLinkingModifiers;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::add_native_library)]
+pub struct AddNativeLibrary {
+    pub library_path: PathBuf,
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::multiple_external_func_decl)]
+pub struct MultipleExternalFuncDecl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub function: Symbol,
+    pub library_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+pub enum LinkRlibError {
+    #[diag(codegen_ssa::rlib_missing_format)]
+    MissingFormat,
+
+    #[diag(codegen_ssa::rlib_only_rmeta_found)]
+    OnlyRmetaFound { crate_name: Symbol },
+
+    #[diag(codegen_ssa::rlib_not_found)]
+    NotFound { crate_name: Symbol },
+}
+
+pub struct ThorinErrorWrapper(pub thorin::Error);
+
+impl IntoDiagnostic<'_> for ThorinErrorWrapper {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag;
+        match self.0 {
+            thorin::Error::ReadInput(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure);
+                diag
+            }
+            thorin::Error::ParseFileKind(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind);
+                diag
+            }
+            thorin::Error::ParseObjectFile(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file);
+                diag
+            }
+            thorin::Error::ParseArchiveFile(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file);
+                diag
+            }
+            thorin::Error::ParseArchiveMember(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member);
+                diag
+            }
+            thorin::Error::InvalidInputKind => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind);
+                diag
+            }
+            thorin::Error::DecompressData(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data);
+                diag
+            }
+            thorin::Error::NamelessSection(_, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
+                diag =
+                    handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::MultipleRelocations(section, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::UnsupportedRelocation(section, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::MissingDwoName(id) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name);
+                diag.set_arg("id", format!("0x{:08x}", id));
+                diag
+            }
+            thorin::Error::NoCompilationUnits => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units);
+                diag
+            }
+            thorin::Error::NoDie => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die);
+                diag
+            }
+            thorin::Error::TopLevelDieNotUnit => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit);
+                diag
+            }
+            thorin::Error::MissingRequiredSection(section) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section);
+                diag.set_arg("section", section);
+                diag
+            }
+            thorin::Error::ParseUnitAbbreviations(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations);
+                diag
+            }
+            thorin::Error::ParseUnitAttribute(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute);
+                diag
+            }
+            thorin::Error::ParseUnitHeader(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header);
+                diag
+            }
+            thorin::Error::ParseUnit(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit);
+                diag
+            }
+            thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version);
+                diag.set_arg("section", section);
+                diag.set_arg("actual", actual);
+                diag.set_arg("format", format);
+                diag
+            }
+            thorin::Error::OffsetAtIndex(_, index) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index);
+                diag.set_arg("index", index);
+                diag
+            }
+            thorin::Error::StrAtOffset(_, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::ParseIndex(_, section) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index);
+                diag.set_arg("section", section);
+                diag
+            }
+            thorin::Error::UnitNotInIndex(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::RowNotInIndex(_, row) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index);
+                diag.set_arg("row", row);
+                diag
+            }
+            thorin::Error::SectionNotInRow => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row);
+                diag
+            }
+            thorin::Error::EmptyUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::MultipleDebugInfoSection => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section);
+                diag
+            }
+            thorin::Error::MultipleDebugTypesSection => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section);
+                diag
+            }
+            thorin::Error::NotSplitUnit => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit);
+                diag
+            }
+            thorin::Error::DuplicateUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::MissingReferencedUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::NoOutputObjectCreated => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created);
+                diag
+            }
+            thorin::Error::MixedInputEncodings => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings);
+                diag
+            }
+            thorin::Error::Io(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_io);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::ObjectRead(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::ObjectWrite(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::GimliRead(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::GimliWrite(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            _ => unimplemented!("Untranslated thorin error"),
+        }
+    }
+}
+
+pub struct LinkingFailed<'a> {
+    pub linker_path: &'a PathBuf,
+    pub exit_status: ExitStatus,
+    pub command: &'a Command,
+    pub escaped_output: &'a str,
+}
+
+impl IntoDiagnostic<'_> for LinkingFailed<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+        diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
+        diag.set_arg("exit_status", format!("{}", self.exit_status));
+
+        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+
+        // Trying to match an error from OS linkers
+        // which by now we have no way to translate.
+        if self.escaped_output.contains("undefined reference to") {
+            diag.note(fluent::codegen_ssa::extern_funcs_not_found)
+                .note(fluent::codegen_ssa::specify_libraries_to_link)
+                .note(fluent::codegen_ssa::use_cargo_directive);
+        }
+        diag
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 3ef9a634e18..ceebe4d417f 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(strict_provenance)]
 #![feature(int_roundings)]
 #![feature(if_let_guard)]
+#![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
@@ -43,6 +44,7 @@ pub mod base;
 pub mod common;
 pub mod coverageinfo;
 pub mod debuginfo;
+pub mod errors;
 pub mod glue;
 pub mod meth;
 pub mod mir;
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
new file mode 100644
index 00000000000..0d0388a039e
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -0,0 +1,119 @@
+codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
+
+codegen_ssa_version_script_write_failure = failed to write version script: {$error}
+
+codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
+
+codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
+
+codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
+
+codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
+
+codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+
+codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
+
+codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
+
+codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
+
+codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
+
+codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+
+codegen_ssa_incompatible_linking_modifiers = the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
+
+codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
+
+codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+
+codegen_ssa_rlib_missing_format = could not find formats for rlibs
+
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+
+codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
+
+codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+
+codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
+
+codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
+
+codegen_ssa_thorin_read_input_failure = failed to read input file
+
+codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+
+codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
+
+codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
+
+codegen_ssa_thorin_parse_archive_member = failed to parse archive member
+
+codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+
+codegen_ssa_thorin_decompress_data = failed to decompress compressed section
+
+codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
+
+codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
+
+codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
+
+codegen_ssa_thorin_no_compilation_units = input object has no compilation units
+
+codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
+
+codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
+
+codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+
+codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
+
+codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
+
+codegen_ssa_thorin_parse_unit_header = failed to parse unit header
+
+codegen_ssa_thorin_parse_unit = failed to parse unit
+
+codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
+
+codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
+
+codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
+
+codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
+
+codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
+
+codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
+
+codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
+
+codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+
+codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+
+codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
+
+codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+
+codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
+
+codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
+
+codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
+
+codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+
+codegen_ssa_thorin_io = {$error}
+codegen_ssa_thorin_object_read = {$error}
+codegen_ssa_thorin_object_write = {$error}
+codegen_ssa_thorin_gimli_read = {$error}
+codegen_ssa_thorin_gimli_write = {$error}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 18be60975e4..a2d507328b3 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -40,9 +40,10 @@ fluent_messages! {
     attr => "../locales/en-US/attr.ftl",
     borrowck => "../locales/en-US/borrowck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
+    codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
+    codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
     compiletest => "../locales/en-US/compiletest.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
-    codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
     driver => "../locales/en-US/driver.ftl",
     expand => "../locales/en-US/expand.ftl",
     hir_analysis => "../locales/en-US/hir_analysis.ftl",
@@ -336,19 +337,6 @@ impl DiagnosticMessage {
             }
         }
     }
-
-    /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
-    /// this diagnostic message is of the legacy, non-translatable variety. Panics if this
-    /// assumption does not hold.
-    ///
-    /// Don't use this - it exists to support some places that do comparison with diagnostic
-    /// strings.
-    pub fn expect_str(&self) -> &str {
-        match self {
-            DiagnosticMessage::Str(s) => s,
-            _ => panic!("expected non-translatable diagnostic message"),
-        }
-    }
 }
 
 /// `From` impl that enables existing diagnostic calls to functions which now take
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 6d2c7aac6af..30aa4f0fa34 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -68,19 +68,22 @@ fn emit_frag_parse_err(
     kind: AstFragmentKind,
 ) {
     // FIXME(davidtwco): avoid depending on the error message text
-    if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found `<eof>`") {
-        if !e.span.is_dummy() {
-            // early end of macro arm (#52866)
-            e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
-        }
+    if parser.token == token::Eof
+        && let DiagnosticMessage::Str(message) = &e.message[0].0
+        && message.ends_with(", found `<eof>`")
+    {
         let msg = &e.message[0];
         e.message[0] = (
-            rustc_errors::DiagnosticMessage::Str(format!(
+            DiagnosticMessage::Str(format!(
                 "macro expansion ends with an incomplete expression: {}",
-                msg.0.expect_str().replace(", found `<eof>`", ""),
+                message.replace(", found `<eof>`", ""),
             )),
             msg.1,
         );
+        if !e.span.is_dummy() {
+            // early end of macro arm (#52866)
+            e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
+        }
     }
     if e.span.is_dummy() {
         // Get around lack of span in error (#30128)
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index f1f0c224bbd..4ef4aad902c 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -464,6 +464,16 @@ impl PartialRes {
     pub fn unresolved_segments(&self) -> usize {
         self.unresolved_segments
     }
+
+    #[inline]
+    pub fn full_res(&self) -> Option<Res<NodeId>> {
+        (self.unresolved_segments == 0).then_some(self.base_res)
+    }
+
+    #[inline]
+    pub fn expect_full_res(&self) -> Res<NodeId> {
+        self.full_res().expect("unexpected unresolved segments")
+    }
 }
 
 /// Different kinds of symbols can coexist even if they share the same textual name.
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index c499364056f..69155a422b0 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -197,6 +197,9 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
 
 /// Enforce that we do not have two items in an impl with the same name.
 fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
+    if tcx.impl_trait_ref(impl_def_id).is_some() {
+        return;
+    }
     let mut seen_type_items = FxHashMap::default();
     let mut seen_value_items = FxHashMap::default();
     for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 8d9a0388e21..45c84680ad2 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -32,7 +32,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(get_mut_unchecked)]
 #![feature(if_let_guard)]
-#![feature(map_first_last)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(extern_types)]
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index c3d87b5b6af..a17793ecd99 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -326,7 +326,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     }
                     PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)),
                     PathResult::NonModule(partial_res) => {
-                        expected_found_error(partial_res.base_res())
+                        expected_found_error(partial_res.expect_full_res())
                     }
                     PathResult::Failed { span, label, suggestion, .. } => {
                         Err(VisResolutionError::FailedToResolve(span, label, suggestion))
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 9a3eac2f866..83aae286402 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1050,6 +1050,19 @@ impl<'a> Resolver<'a> {
                 err.span_label(trait_item_span, "item in trait");
                 err
             }
+            ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
+                let mut err = struct_span_err!(
+                    self.session,
+                    span,
+                    E0201,
+                    "duplicate definitions with name `{}`:",
+                    name,
+                );
+                err.span_label(old_span, "previous definition here");
+                err.span_label(trait_item_span, "item in trait");
+                err.span_label(span, "duplicate definition");
+                err
+            }
             ResolutionError::InvalidAsmSym => {
                 let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
                 err.span_label(span, "is a local variable");
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c08f4a7204d..776c8ad528c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -641,8 +641,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 // Check whether we should interpret this as a bare trait object.
                 if qself.is_none()
                     && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
-                    && partial_res.unresolved_segments() == 0
-                    && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+                    && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
                 {
                     // This path is actually a bare trait object.  In case of a bare `Fn`-trait
                     // object with anonymous lifetimes, we need this rib to correctly place the
@@ -1929,7 +1928,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 match ty.kind {
                     TyKind::ImplicitSelf => true,
                     TyKind::Path(None, _) => {
-                        let path_res = self.r.partial_res_map[&ty.id].base_res();
+                        let path_res = self.r.partial_res_map[&ty.id].expect_full_res();
                         if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res {
                             return true;
                         }
@@ -1970,7 +1969,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     None
                 }
             })
-            .map(|res| res.base_res())
+            .map(|res| res.expect_full_res())
             .filter(|res| {
                 // Permit the types that unambiguously always
                 // result in the same type constructor being used
@@ -2530,7 +2529,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
             self.diagnostic_metadata.currently_processing_impl_trait = None;
-            if let Some(def_id) = res.base_res().opt_def_id() {
+            if let Some(def_id) = res.expect_full_res().opt_def_id() {
                 new_id = Some(def_id);
                 new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
             }
@@ -2618,8 +2617,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                         this.with_current_self_type(self_type, |this| {
                                             this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
                                                 debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+                                                let mut seen_trait_items = Default::default();
                                                 for item in impl_items {
-                                                    this.resolve_impl_item(&**item);
+                                                    this.resolve_impl_item(&**item, &mut seen_trait_items);
                                                 }
                                             });
                                         });
@@ -2633,7 +2633,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         );
     }
 
-    fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
+    fn resolve_impl_item(
+        &mut self,
+        item: &'ast AssocItem,
+        seen_trait_items: &mut FxHashMap<DefId, Span>,
+    ) {
         use crate::ResolutionError::*;
         match &item.kind {
             AssocItemKind::Const(_, ty, default) => {
@@ -2646,6 +2650,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     &item.kind,
                     ValueNS,
                     item.span,
+                    seen_trait_items,
                     |i, s, c| ConstNotMemberOfTrait(i, s, c),
                 );
 
@@ -2686,6 +2691,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             &item.kind,
                             ValueNS,
                             item.span,
+                            seen_trait_items,
                             |i, s, c| MethodNotMemberOfTrait(i, s, c),
                         );
 
@@ -2714,6 +2720,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                 &item.kind,
                                 TypeNS,
                                 item.span,
+                                seen_trait_items,
                                 |i, s, c| TypeNotMemberOfTrait(i, s, c),
                             );
 
@@ -2735,6 +2742,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         kind: &AssocItemKind,
         ns: Namespace,
         span: Span,
+        seen_trait_items: &mut FxHashMap<DefId, Span>,
         err: F,
     ) where
         F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
@@ -2767,7 +2775,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         };
 
         let res = binding.res();
-        let Res::Def(def_kind, _) = res else { bug!() };
+        let Res::Def(def_kind, id_in_trait) = res else { bug!() };
+
+        match seen_trait_items.entry(id_in_trait) {
+            Entry::Occupied(entry) => {
+                self.report_error(
+                    span,
+                    ResolutionError::TraitImplDuplicate {
+                        name: ident.name,
+                        old_span: *entry.get(),
+                        trait_item_span: binding.span,
+                    },
+                );
+                return;
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(span);
+            }
+        };
+
         match (def_kind, kind) {
             (DefKind::AssocTy, AssocItemKind::Type(..))
             | (DefKind::AssocFn, AssocItemKind::Fn(..))
@@ -2859,7 +2885,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     fn is_base_res_local(&self, nid: NodeId) -> bool {
-        matches!(self.r.partial_res_map.get(&nid).map(|res| res.base_res()), Some(Res::Local(..)))
+        matches!(
+            self.r.partial_res_map.get(&nid).map(|res| res.expect_full_res()),
+            Some(Res::Local(..))
+        )
     }
 
     /// Checks that all of the arms in an or-pattern have exactly the
@@ -3346,12 +3375,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             source.defer_to_typeck(),
             finalize,
         ) {
-            Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => {
-                if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err
-                {
+            Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => {
+                if source.is_expected(res) || res == Res::Err {
                     partial_res
                 } else {
-                    report_errors(self, Some(partial_res.base_res()))
+                    report_errors(self, Some(res))
                 }
             }
 
@@ -3559,20 +3587,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         };
 
         if path.len() > 1
-            && result.base_res() != Res::Err
+            && let Some(res) = result.full_res()
+            && res != Res::Err
             && path[0].ident.name != kw::PathRoot
             && path[0].ident.name != kw::DollarCrate
         {
             let unqualified_result = {
                 match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
-                    PathResult::NonModule(path_res) => path_res.base_res(),
+                    PathResult::NonModule(path_res) => path_res.expect_full_res(),
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         module.res().unwrap()
                     }
                     _ => return Ok(Some(result)),
                 }
             };
-            if result.base_res() == unqualified_result {
+            if res == unqualified_result {
                 let lint = lint::builtin::UNUSED_QUALIFICATIONS;
                 self.r.lint_buffer.buffer_lint(
                     lint,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c05f89a6575..13cd7987e92 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -968,11 +968,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
                 return false;
             };
-            if !(matches!(
-                partial_res.base_res(),
-                hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
-            ) && partial_res.unresolved_segments() == 0)
-            {
+            if !matches!(
+                partial_res.full_res(),
+                Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
+            ) {
                 return false;
             }
             (ty, position, path)
@@ -986,11 +985,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
                 return false;
             };
-            if !(matches!(
-                partial_res.base_res(),
-                hir::def::Res::Def(hir::def::DefKind::TyParam, _)
-            ) && partial_res.unresolved_segments() == 0)
-            {
+            if !matches!(
+                partial_res.full_res(),
+                Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
+            ) {
                 return false;
             }
             if let (
@@ -1518,20 +1516,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             {
                 // Look for a field with the same name in the current self_type.
                 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
-                    match resolution.base_res() {
-                        Res::Def(DefKind::Struct | DefKind::Union, did)
-                            if resolution.unresolved_segments() == 0 =>
-                        {
-                            if let Some(field_names) = self.r.field_names.get(&did) {
-                                if field_names
-                                    .iter()
-                                    .any(|&field_name| ident.name == field_name.node)
-                                {
-                                    return Some(AssocSuggestion::Field);
-                                }
+                    if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
+                        resolution.full_res()
+                    {
+                        if let Some(field_names) = self.r.field_names.get(&did) {
+                            if field_names.iter().any(|&field_name| ident.name == field_name.node) {
+                                return Some(AssocSuggestion::Field);
                             }
                         }
-                        _ => {}
                     }
                 }
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 095a57ae24f..971cd62831d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -235,6 +235,8 @@ enum ResolutionError<'a> {
         trait_item_span: Span,
         code: rustc_errors::DiagnosticId,
     },
+    /// Error E0201: multiple impl items for the same trait item.
+    TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
     /// Inline asm `sym` operand must refer to a `fn` or `static`.
     InvalidAsmSym,
 }
@@ -1881,12 +1883,10 @@ impl<'a> Resolver<'a> {
 
         match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
-            PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
-                Some(path_res.base_res())
+            PathResult::NonModule(path_res) => path_res.full_res(),
+            PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
+                None
             }
-            PathResult::Module(ModuleOrUniformRoot::ExternPrelude)
-            | PathResult::NonModule(..)
-            | PathResult::Failed { .. } => None,
             PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
         }
     }
@@ -1937,12 +1937,8 @@ impl<'a> Resolver<'a> {
                 return None;
             }
 
-            let partial_res = self.partial_res_map.get(&expr.id)?;
-            if partial_res.unresolved_segments() != 0 {
-                return None;
-            }
-
-            if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() {
+            let res = self.partial_res_map.get(&expr.id)?.full_res()?;
+            if let Res::Def(def::DefKind::Fn, def_id) = res {
                 // We only support cross-crate argument rewriting. Uses
                 // within the same crate should be updated to use the new
                 // const generics style.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index dafa10e9e00..f6f0b3c1139 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -590,9 +590,7 @@ impl<'a> Resolver<'a> {
 
         let res = if path.len() > 1 {
             let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
-                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
-                    Ok(path_res.base_res())
-                }
+                PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                 PathResult::NonModule(..)
                 | PathResult::Indeterminate
@@ -692,9 +690,8 @@ impl<'a> Resolver<'a> {
                 Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
             ) {
-                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
-                    let res = path_res.base_res();
-                    check_consistency(self, &path, path_span, kind, initial_res, res);
+                PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
+                    check_consistency(self, &path, path_span, kind, initial_res, res)
                 }
                 path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
                     let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {