about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs3
-rw-r--r--compiler/rustc_driver/src/lib.rs6
-rw-r--r--compiler/rustc_errors/src/emitter.rs11
-rw-r--r--compiler/rustc_errors/src/error.rs137
-rw-r--r--compiler/rustc_errors/src/json.rs9
-rw-r--r--compiler/rustc_errors/src/lib.rs55
-rw-r--r--compiler/rustc_errors/src/tests.rs188
-rw-r--r--compiler/rustc_errors/src/translation.rs117
-rw-r--r--compiler/rustc_hir/src/hir_id.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs6
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs38
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/query.rs4
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs4
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs83
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs17
-rw-r--r--library/core/tests/time.rs26
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs4
-rw-r--r--triagebot.toml7
25 files changed, 550 insertions, 198 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index e4f716c3194..a61d3ab40a5 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -40,12 +40,11 @@ where
                         let index = index
                             .try_into()
                             .expect("more generic parameters than can fit into a `u32`");
-                        let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
                         // Only recurse when generic parameters in fns, closures and generators
                         // are used and require substitution.
                         // Just in case there are closures or generators within this subst,
                         // recurse.
-                        if is_used && subst.needs_subst() {
+                        if unused_params.is_used(index) && subst.needs_subst() {
                             return subst.visit_with(self);
                         }
                     }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 3cbe0052359..fcb73c64356 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1196,8 +1196,8 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
             };
 
             // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            // Don't do this for `GoodPathBug`, which already emits its own more useful backtrace.
-            if !info.payload().is::<rustc_errors::GoodPathBug>() {
+            // Don't do this for delayed bugs, which already emit their own more useful backtrace.
+            if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
                 (*DEFAULT_HOOK)(info);
 
                 // Separate the output with an empty line
@@ -1235,7 +1235,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // a .span_bug or .bug call has already printed what
     // it wants to print.
     if !info.payload().is::<rustc_errors::ExplicitBug>()
-        && !info.payload().is::<rustc_errors::GoodPathBug>()
+        && !info.payload().is::<rustc_errors::DelayedBugPanic>()
     {
         let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
         handler.emit_diagnostic(&mut d);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 0ca200abe19..7f01df32101 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -28,6 +28,7 @@ use rustc_error_messages::{FluentArgs, SpanLabel};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use std::borrow::Cow;
 use std::cmp::{max, min, Reverse};
+use std::error::Report;
 use std::io::prelude::*;
 use std::io::{self, IsTerminal};
 use std::iter;
@@ -250,7 +251,7 @@ pub trait Emitter: Translate {
         let mut primary_span = diag.span.clone();
         let suggestions = diag.suggestions.as_deref().unwrap_or(&[]);
         if let Some((sugg, rest)) = suggestions.split_first() {
-            let msg = self.translate_message(&sugg.msg, fluent_args);
+            let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
             if rest.is_empty() &&
                // ^ if there is only one suggestion
                // don't display multi-suggestions as labels
@@ -1325,7 +1326,7 @@ impl EmitterWriter {
         //                very *weird* formats
         //                see?
         for (text, style) in msg.iter() {
-            let text = self.translate_message(text, args);
+            let text = self.translate_message(text, args).map_err(Report::new).unwrap();
             let lines = text.split('\n').collect::<Vec<_>>();
             if lines.len() > 1 {
                 for (i, line) in lines.iter().enumerate() {
@@ -1387,7 +1388,7 @@ impl EmitterWriter {
                 label_width += 2;
             }
             for (text, _) in msg.iter() {
-                let text = self.translate_message(text, args);
+                let text = self.translate_message(text, args).map_err(Report::new).unwrap();
                 // Account for newlines to align output to its label.
                 for (line, text) in normalize_whitespace(&text).lines().enumerate() {
                     buffer.append(
@@ -2301,7 +2302,9 @@ impl FileWithAnnotatedLines {
                     hi.col_display += 1;
                 }
 
-                let label = label.as_ref().map(|m| emitter.translate_message(m, args).to_string());
+                let label = label.as_ref().map(|m| {
+                    emitter.translate_message(m, args).map_err(Report::new).unwrap().to_string()
+                });
 
                 if lo.line != hi.line {
                     let ml = MultilineAnnotation {
diff --git a/compiler/rustc_errors/src/error.rs b/compiler/rustc_errors/src/error.rs
new file mode 100644
index 00000000000..ec0a2fe8cd8
--- /dev/null
+++ b/compiler/rustc_errors/src/error.rs
@@ -0,0 +1,137 @@
+use rustc_error_messages::{
+    fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
+    FluentArgs, FluentError,
+};
+use std::borrow::Cow;
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
+pub enum TranslateError<'args> {
+    One {
+        id: &'args Cow<'args, str>,
+        args: &'args FluentArgs<'args>,
+        kind: TranslateErrorKind<'args>,
+    },
+    Two {
+        primary: Box<TranslateError<'args>>,
+        fallback: Box<TranslateError<'args>>,
+    },
+}
+
+impl<'args> TranslateError<'args> {
+    pub fn message(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+        Self::One { id, args, kind: TranslateErrorKind::MessageMissing }
+    }
+    pub fn primary(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+        Self::One { id, args, kind: TranslateErrorKind::PrimaryBundleMissing }
+    }
+    pub fn attribute(
+        id: &'args Cow<'args, str>,
+        args: &'args FluentArgs<'args>,
+        attr: &'args str,
+    ) -> Self {
+        Self::One { id, args, kind: TranslateErrorKind::AttributeMissing { attr } }
+    }
+    pub fn value(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+        Self::One { id, args, kind: TranslateErrorKind::ValueMissing }
+    }
+
+    pub fn fluent(
+        id: &'args Cow<'args, str>,
+        args: &'args FluentArgs<'args>,
+        errs: Vec<FluentError>,
+    ) -> Self {
+        Self::One { id, args, kind: TranslateErrorKind::Fluent { errs } }
+    }
+
+    pub fn and(self, fallback: TranslateError<'args>) -> TranslateError<'args> {
+        Self::Two { primary: Box::new(self), fallback: Box::new(fallback) }
+    }
+}
+
+#[derive(Debug)]
+pub enum TranslateErrorKind<'args> {
+    MessageMissing,
+    PrimaryBundleMissing,
+    AttributeMissing { attr: &'args str },
+    ValueMissing,
+    Fluent { errs: Vec<FluentError> },
+}
+
+impl fmt::Display for TranslateError<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use TranslateErrorKind::*;
+
+        match self {
+            Self::One { id, args, kind } => {
+                writeln!(f, "failed while formatting fluent string `{id}`: ")?;
+                match kind {
+                    MessageMissing => writeln!(f, "message was missing")?,
+                    PrimaryBundleMissing => writeln!(f, "the primary bundle was missing")?,
+                    AttributeMissing { attr } => {
+                        writeln!(f, "the attribute `{attr}` was missing")?;
+                        writeln!(f, "help: add `.{attr} = <message>`")?;
+                    }
+                    ValueMissing => writeln!(f, "the value was missing")?,
+                    Fluent { errs } => {
+                        for err in errs {
+                            match err {
+                                FluentError::ResolverError(ResolverError::Reference(
+                                    ReferenceKind::Message { id, .. }
+                                    | ReferenceKind::Variable { id, .. },
+                                )) => {
+                                    if args.iter().any(|(arg_id, _)| arg_id == id) {
+                                        writeln!(
+                                            f,
+                                            "argument `{id}` exists but was not referenced correctly"
+                                        )?;
+                                        writeln!(f, "help: try using `{{${id}}}` instead")?;
+                                    } else {
+                                        writeln!(
+                                            f,
+                                            "the fluent string has an argument `{id}` that was not found."
+                                        )?;
+                                        let vars: Vec<&str> =
+                                            args.iter().map(|(a, _v)| a).collect();
+                                        match &*vars {
+                                            [] => writeln!(f, "help: no arguments are available")?,
+                                            [one] => writeln!(
+                                                f,
+                                                "help: the argument `{one}` is available"
+                                            )?,
+                                            [first, middle @ .., last] => {
+                                                write!(f, "help: the arguments `{first}`")?;
+                                                for a in middle {
+                                                    write!(f, ", `{a}`")?;
+                                                }
+                                                writeln!(f, " and `{last}` are available")?;
+                                            }
+                                        }
+                                    }
+                                }
+                                _ => writeln!(f, "{err}")?,
+                            }
+                        }
+                    }
+                }
+            }
+            // If someone cares about primary bundles, they'll probably notice it's missing
+            // regardless or will be using `debug_assertions`
+            // so we skip the arm below this one to avoid confusing the regular user.
+            Self::Two { primary: box Self::One { kind: PrimaryBundleMissing, .. }, fallback } => {
+                fmt::Display::fmt(fallback, f)?;
+            }
+            Self::Two { primary, fallback } => {
+                writeln!(
+                    f,
+                    "first, fluent formatting using the primary bundle failed:\n {primary}\n \
+                    while attempting to recover by using the fallback bundle instead, another error occurred:\n{fallback}"
+                )?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl Error for TranslateError<'_> {}
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index a37073d8fa3..dc38b8725ad 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -24,6 +24,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_error_messages::FluentArgs;
 use rustc_span::hygiene::ExpnData;
 use rustc_span::Span;
+use std::error::Report;
 use std::io::{self, Write};
 use std::path::Path;
 use std::sync::{Arc, Mutex};
@@ -321,7 +322,8 @@ impl Diagnostic {
     fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
         let args = to_fluent_args(diag.args());
         let sugg = diag.suggestions.iter().flatten().map(|sugg| {
-            let translated_message = je.translate_message(&sugg.msg, &args);
+            let translated_message =
+                je.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap();
             Diagnostic {
                 message: translated_message.to_string(),
                 code: None,
@@ -411,7 +413,10 @@ impl DiagnosticSpan {
         Self::from_span_etc(
             span.span,
             span.is_primary,
-            span.label.as_ref().map(|m| je.translate_message(m, args)).map(|m| m.to_string()),
+            span.label
+                .as_ref()
+                .map(|m| je.translate_message(m, args).unwrap())
+                .map(|m| m.to_string()),
             suggestion,
             je,
         )
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b4d23e96f8f..535812fb0e2 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -11,6 +11,10 @@
 #![feature(never_type)]
 #![feature(result_option_inspect)]
 #![feature(rustc_attrs)]
+#![feature(yeet_expr)]
+#![feature(try_blocks)]
+#![feature(box_patterns)]
+#![feature(error_reporter)]
 #![allow(incomplete_features)]
 
 #[macro_use]
@@ -40,8 +44,8 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::HashStableContext;
 use rustc_span::{Loc, Span};
 
-use std::any::Any;
 use std::borrow::Cow;
+use std::error::Report;
 use std::fmt;
 use std::hash::Hash;
 use std::num::NonZeroUsize;
@@ -55,11 +59,14 @@ mod diagnostic;
 mod diagnostic_builder;
 mod diagnostic_impls;
 pub mod emitter;
+pub mod error;
 pub mod json;
 mod lock;
 pub mod registry;
 mod snippet;
 mod styled_buffer;
+#[cfg(test)]
+mod tests;
 pub mod translation;
 
 pub use diagnostic_builder::IntoDiagnostic;
@@ -364,9 +371,9 @@ pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
 /// or `.span_bug` rather than a failed assertion, etc.
 pub struct ExplicitBug;
 
-/// Signifies that the compiler died with an explicit call to `.delay_good_path_bug`
+/// Signifies that the compiler died with an explicit call to `.delay_*_bug`
 /// rather than a failed assertion, etc.
-pub struct GoodPathBug;
+pub struct DelayedBugPanic;
 
 pub use diagnostic::{
     AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
@@ -399,7 +406,7 @@ struct HandlerInner {
     warn_count: usize,
     deduplicated_err_count: usize,
     emitter: Box<dyn Emitter + sync::Send>,
-    delayed_span_bugs: Vec<Diagnostic>,
+    delayed_span_bugs: Vec<DelayedDiagnostic>,
     delayed_good_path_bugs: Vec<DelayedDiagnostic>,
     /// This flag indicates that an expected diagnostic was emitted and suppressed.
     /// This is used for the `delayed_good_path_bugs` check.
@@ -505,11 +512,7 @@ impl Drop for HandlerInner {
 
         if !self.has_errors() {
             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
-            self.flush_delayed(
-                bugs,
-                "no errors encountered even though `delay_span_bug` issued",
-                ExplicitBug,
-            );
+            self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
         }
 
         // FIXME(eddyb) this explains what `delayed_good_path_bugs` are!
@@ -520,9 +523,8 @@ impl Drop for HandlerInner {
         if !self.has_any_message() && !self.suppressed_expected_diag {
             let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
             self.flush_delayed(
-                bugs.into_iter().map(DelayedDiagnostic::decorate),
+                bugs,
                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
-                GoodPathBug,
             );
         }
 
@@ -622,7 +624,14 @@ impl Handler {
     ) -> SubdiagnosticMessage {
         let inner = self.inner.borrow();
         let args = crate::translation::to_fluent_args(args);
-        SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string())
+        SubdiagnosticMessage::Eager(
+            inner
+                .emitter
+                .translate_message(&message, &args)
+                .map_err(Report::new)
+                .unwrap()
+                .to_string(),
+        )
     }
 
     // This is here to not allow mutation of flags;
@@ -1223,11 +1232,7 @@ impl Handler {
     pub fn flush_delayed(&self) {
         let mut inner = self.inner.lock();
         let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new());
-        inner.flush_delayed(
-            bugs,
-            "no errors encountered even though `delay_span_bug` issued",
-            ExplicitBug,
-        );
+        inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
     }
 }
 
@@ -1287,7 +1292,9 @@ impl HandlerInner {
             // once *any* errors were emitted (and truncate `delayed_span_bugs`
             // when an error is first emitted, also), but maybe there's a case
             // in which that's not sound? otherwise this is really inefficient.
-            self.delayed_span_bugs.push(diagnostic.clone());
+            let backtrace = std::backtrace::Backtrace::force_capture();
+            self.delayed_span_bugs
+                .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
 
             if !self.flags.report_delayed_bugs {
                 return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
@@ -1562,7 +1569,6 @@ impl HandlerInner {
         }
         let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
         diagnostic.set_span(sp.into());
-        diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
         self.emit_diagnostic(&mut diagnostic).unwrap()
     }
 
@@ -1605,12 +1611,13 @@ impl HandlerInner {
 
     fn flush_delayed(
         &mut self,
-        bugs: impl IntoIterator<Item = Diagnostic>,
+        bugs: impl IntoIterator<Item = DelayedDiagnostic>,
         explanation: impl Into<DiagnosticMessage> + Copy,
-        panic_with: impl Any + Send + 'static,
     ) {
         let mut no_bugs = true;
-        for mut bug in bugs {
+        for bug in bugs {
+            let mut bug = bug.decorate();
+
             if no_bugs {
                 // Put the overall explanation before the `DelayedBug`s, to
                 // frame them better (e.g. separate warnings from them).
@@ -1633,9 +1640,9 @@ impl HandlerInner {
             self.emit_diagnostic(&mut bug);
         }
 
-        // Panic with `ExplicitBug` to avoid "unexpected panic" messages.
+        // Panic with `DelayedBugPanic` to avoid "unexpected panic" messages.
         if !no_bugs {
-            panic::panic_any(panic_with);
+            panic::panic_any(DelayedBugPanic);
         }
     }
 
diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs
new file mode 100644
index 00000000000..52103e46097
--- /dev/null
+++ b/compiler/rustc_errors/src/tests.rs
@@ -0,0 +1,188 @@
+use crate::error::{TranslateError, TranslateErrorKind};
+use crate::fluent_bundle::*;
+use crate::translation::Translate;
+use crate::FluentBundle;
+use rustc_data_structures::sync::Lrc;
+use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
+use rustc_error_messages::langid;
+use rustc_error_messages::DiagnosticMessage;
+
+struct Dummy {
+    bundle: FluentBundle,
+}
+
+impl Translate for Dummy {
+    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+        None
+    }
+
+    fn fallback_fluent_bundle(&self) -> &FluentBundle {
+        &self.bundle
+    }
+}
+
+fn make_dummy(ftl: &'static str) -> Dummy {
+    let resource = FluentResource::try_new(ftl.into()).expect("Failed to parse an FTL string.");
+
+    let langid_en = langid!("en-US");
+
+    #[cfg(parallel_compiler)]
+    let mut bundle = FluentBundle::new_concurrent(vec![langid_en]);
+
+    #[cfg(not(parallel_compiler))]
+    let mut bundle = FluentBundle::new(vec![langid_en]);
+
+    bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle.");
+
+    Dummy { bundle }
+}
+
+#[test]
+fn wellformed_fluent() {
+    let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{$name}` here
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .value_borrowed_label = value borrowed here after move
+    .suggestion = borrow this binding in the pattern to avoid moving the value");
+
+    let mut args = FluentArgs::new();
+    args.set("name", "Foo");
+    args.set("ty", "std::string::String");
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("suggestion".into()),
+        );
+
+        assert_eq!(
+            dummy.translate_message(&message, &args).unwrap(),
+            "borrow this binding in the pattern to avoid moving the value"
+        );
+    }
+
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("value_borrowed_label".into()),
+        );
+
+        assert_eq!(
+            dummy.translate_message(&message, &args).unwrap(),
+            "value borrowed here after move"
+        );
+    }
+
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("occurs_because_label".into()),
+        );
+
+        assert_eq!(
+            dummy.translate_message(&message, &args).unwrap(),
+            "move occurs because `\u{2068}Foo\u{2069}` has type `\u{2068}std::string::String\u{2069}` which does not implement the `Copy` trait"
+        );
+
+        {
+            let message = DiagnosticMessage::FluentIdentifier(
+                "mir_build_borrow_of_moved_value".into(),
+                Some("label".into()),
+            );
+
+            assert_eq!(
+                dummy.translate_message(&message, &args).unwrap(),
+                "value moved into `\u{2068}Foo\u{2069}` here"
+            );
+        }
+    }
+}
+
+#[test]
+fn misformed_fluent() {
+    let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{name}` here
+    .occurs_because_label = move occurs because `{$oops}` has type `{$ty}` which does not implement the `Copy` trait
+    .suggestion = borrow this binding in the pattern to avoid moving the value");
+
+    let mut args = FluentArgs::new();
+    args.set("name", "Foo");
+    args.set("ty", "std::string::String");
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("value_borrowed_label".into()),
+        );
+
+        let err = dummy.translate_message(&message, &args).unwrap_err();
+        assert!(
+            matches!(
+                &err,
+                TranslateError::Two {
+                    primary: box TranslateError::One {
+                        kind: TranslateErrorKind::PrimaryBundleMissing,
+                        ..
+                    },
+                    fallback: box TranslateError::One {
+                        kind: TranslateErrorKind::AttributeMissing { attr: "value_borrowed_label" },
+                        ..
+                    }
+                }
+            ),
+            "{err:#?}"
+        );
+        assert_eq!(
+            format!("{err}"),
+            "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nthe attribute `value_borrowed_label` was missing\nhelp: add `.value_borrowed_label = <message>`\n"
+        );
+    }
+
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("label".into()),
+        );
+
+        let err = dummy.translate_message(&message, &args).unwrap_err();
+        if let TranslateError::Two {
+            primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
+            fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
+        } = &err
+            && let [FluentError::ResolverError(ResolverError::Reference(
+                ReferenceKind::Message { id, .. }
+                    | ReferenceKind::Variable { id, .. },
+            ))] = &**errs
+            && id == "name"
+        {} else {
+            panic!("{err:#?}")
+        };
+        assert_eq!(
+            format!("{err}"),
+            "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nargument `name` exists but was not referenced correctly\nhelp: try using `{$name}` instead\n"
+        );
+    }
+
+    {
+        let message = DiagnosticMessage::FluentIdentifier(
+            "mir_build_borrow_of_moved_value".into(),
+            Some("occurs_because_label".into()),
+        );
+
+        let err = dummy.translate_message(&message, &args).unwrap_err();
+        if let TranslateError::Two {
+            primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
+            fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
+        } = &err
+            && let [FluentError::ResolverError(ResolverError::Reference(
+                ReferenceKind::Message { id, .. }
+                    | ReferenceKind::Variable { id, .. },
+            ))] = &**errs
+            && id == "oops"
+        {} else {
+            panic!("{err:#?}")
+        };
+        assert_eq!(
+            format!("{err}"),
+            "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nthe fluent string has an argument `oops` that was not found.\nhelp: the arguments `name` and `ty` are available\n"
+        );
+    }
+}
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index afd660ff1bf..addfc9726ca 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -1,11 +1,10 @@
+use crate::error::TranslateError;
 use crate::snippet::Style;
 use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
 use rustc_data_structures::sync::Lrc;
-use rustc_error_messages::{
-    fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
-    FluentArgs, FluentError,
-};
+use rustc_error_messages::FluentArgs;
 use std::borrow::Cow;
+use std::error::Report;
 
 /// Convert diagnostic arguments (a rustc internal type that exists to implement
 /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
@@ -46,7 +45,10 @@ pub trait Translate {
         args: &FluentArgs<'_>,
     ) -> Cow<'_, str> {
         Cow::Owned(
-            messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
+            messages
+                .iter()
+                .map(|(m, _)| self.translate_message(m, args).map_err(Report::new).unwrap())
+                .collect::<String>(),
         )
     }
 
@@ -55,83 +57,56 @@ pub trait Translate {
         &'a self,
         message: &'a DiagnosticMessage,
         args: &'a FluentArgs<'_>,
-    ) -> Cow<'_, str> {
+    ) -> Result<Cow<'_, str>, TranslateError<'_>> {
         trace!(?message, ?args);
         let (identifier, attr) = match message {
             DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
-                return Cow::Borrowed(msg);
+                return Ok(Cow::Borrowed(msg));
             }
             DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
         };
+        let translate_with_bundle =
+            |bundle: &'a FluentBundle| -> Result<Cow<'_, str>, TranslateError<'_>> {
+                let message = bundle
+                    .get_message(identifier)
+                    .ok_or(TranslateError::message(identifier, args))?;
+                let value = match attr {
+                    Some(attr) => message
+                        .get_attribute(attr)
+                        .ok_or(TranslateError::attribute(identifier, args, attr))?
+                        .value(),
+                    None => message.value().ok_or(TranslateError::value(identifier, args))?,
+                };
+                debug!(?message, ?value);
 
-        let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
-            let message = bundle.get_message(identifier)?;
-            let value = match attr {
-                Some(attr) => message.get_attribute(attr)?.value(),
-                None => message.value()?,
+                let mut errs = vec![];
+                let translated = bundle.format_pattern(value, Some(args), &mut errs);
+                debug!(?translated, ?errs);
+                if errs.is_empty() {
+                    Ok(translated)
+                } else {
+                    Err(TranslateError::fluent(identifier, args, errs))
+                }
             };
-            debug!(?message, ?value);
-
-            let mut errs = vec![];
-            let translated = bundle.format_pattern(value, Some(args), &mut errs);
-            debug!(?translated, ?errs);
-            Some((translated, errs))
-        };
 
-        self.fluent_bundle()
-            .and_then(|bundle| translate_with_bundle(bundle))
-            // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
-            // just that the primary bundle doesn't contain the message being translated, so
-            // proceed to the fallback bundle.
-            //
-            // However, when errors are produced from translation, then that means the translation
-            // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
-            //
-            // In debug builds, assert so that compiler devs can spot the broken translation and
-            // fix it..
-            .inspect(|(_, errs)| {
-                debug_assert!(
-                    errs.is_empty(),
-                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
-                    identifier,
-                    attr,
-                    args,
-                    errs
-                );
-            })
-            // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
-            // just hide it and try with the fallback bundle.
-            .filter(|(_, errs)| errs.is_empty())
-            .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
-            .map(|(translated, errs)| {
-                // Always bail out for errors with the fallback bundle.
+        try {
+            match self.fluent_bundle().map(|b| translate_with_bundle(b)) {
+                // The primary bundle was present and translation succeeded
+                Some(Ok(t)) => t,
 
-                let mut help_messages = vec![];
+                // Always yeet out for errors on debug
+                Some(Err(primary)) if cfg!(debug_assertions) => do yeet primary,
 
-                if !errs.is_empty() {
-                    for error in &errs {
-                        match error {
-                            FluentError::ResolverError(ResolverError::Reference(
-                                ReferenceKind::Message { id, .. },
-                            )) if args.iter().any(|(arg_id, _)| arg_id == id) => {
-                                help_messages.push(format!("Argument `{id}` exists but was not referenced correctly. Try using `{{${id}}}` instead"));
-                            }
-                            _ => {}
-                        }
-                    }
+                // If `translate_with_bundle` returns `Err` with the primary bundle, this is likely
+                // just that the primary bundle doesn't contain the message being translated or
+                // something else went wrong) so proceed to the fallback bundle.
+                Some(Err(primary)) => translate_with_bundle(self.fallback_fluent_bundle())
+                    .map_err(|fallback| primary.and(fallback))?,
 
-                    panic!(
-                        "Encountered errors while formatting message for `{identifier}`\n\
-                        help: {}\n\
-                        attr: `{attr:?}`\n\
-                        args: `{args:?}`\n\
-                        errors: `{errs:?}`",
-                        help_messages.join("\nhelp: ")
-                    );
-                }
-
-                translated
-            })
-            .expect("failed to find message in primary or fallback fluent bundles")
+                // The primary bundle is missing, proceed to the fallback bundle
+                None => translate_with_bundle(self.fallback_fluent_bundle())
+                    .map_err(|fallback| TranslateError::primary(identifier, args).and(fallback))?,
+            }
+        }
     }
 }
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 3b4add0cf4d..404abe2b068 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -148,7 +148,7 @@ rustc_index::newtype_index! {
     /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
     /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
     /// the node's position within the owning item in any way, but there is a
-    /// guarantee that the `LocalItemId`s within an owner occupy a dense range of
+    /// guarantee that the `ItemLocalId`s within an owner occupy a dense range of
     /// integers starting at zero, so a mapping that maps all or most nodes within
     /// an "item-like" to something else can be implemented by a `Vec` instead of a
     /// tree or hash map.
@@ -161,7 +161,7 @@ impl ItemLocalId {
     pub const INVALID: ItemLocalId = ItemLocalId::MAX;
 }
 
-// Safety: Ord is implement as just comparing the LocalItemId's numerical
+// Safety: Ord is implement as just comparing the ItemLocalId's numerical
 // values and these are not changed by (de-)serialization.
 unsafe impl StableOrd for ItemLocalId {}
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 0d9f216700f..bdc4ae391f0 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1429,7 +1429,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             let instance =
                 ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
             let unused = tcx.unused_generic_params(instance);
-            if !unused.is_empty() {
+            if !unused.all_used() {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
         }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 26a41f633ff..bf9be714daf 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -13,7 +13,7 @@ use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items::LangItem;
-use rustc_index::bit_set::{BitSet, FiniteBitSet};
+use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, ReprOptions, Ty};
+use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
 use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -384,7 +384,7 @@ define_tables! {
     trait_item_def_id: Table<DefIndex, RawDefId>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
-    unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
+    unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
     params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
     repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 37db2274f67..076ce1bdb34 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1839,7 +1839,7 @@ rustc_queries! {
         desc { "getting codegen unit `{sym}`" }
     }
 
-    query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+    query unused_generic_params(key: ty::InstanceDef<'tcx>) -> UnusedGenericParams {
         cache_on_disk_if { key.def_id().is_local() }
         desc {
             |tcx| "determining which generic parameters are unused by `{}`",
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 35d369ffc89..4ee4d7caec1 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -6,6 +6,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::lang_items::LangItem;
+use rustc_index::bit_set::FiniteBitSet;
 use rustc_macros::HashStable;
 use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
 use rustc_span::Symbol;
@@ -711,7 +712,7 @@ fn polymorphize<'tcx>(
     }
 
     InternalSubsts::for_item(tcx, def_id, |param, _| {
-        let is_unused = unused.contains(param.index).unwrap_or(false);
+        let is_unused = unused.is_unused(param.index);
         debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
         match param.kind {
             // Upvar case: If parameter is a type parameter..
@@ -733,7 +734,7 @@ fn polymorphize<'tcx>(
             // Simple case: If parameter is a const or type parameter..
             ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
                 // ..and is within range and unused..
-                unused.contains(param.index).unwrap_or(false) =>
+                unused.is_unused(param.index) =>
                     // ..then use the identity for this parameter.
                     tcx.mk_param_from_def(param),
 
@@ -774,3 +775,36 @@ fn needs_fn_once_adapter_shim(
         (ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce, _) => Err(()),
     }
 }
+
+// Set bits represent unused generic parameters.
+// An empty set indicates that all parameters are used.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)]
+pub struct UnusedGenericParams(FiniteBitSet<u32>);
+
+impl UnusedGenericParams {
+    pub fn new_all_unused(amount: u32) -> Self {
+        let mut bitset = FiniteBitSet::new_empty();
+        bitset.set_range(0..amount);
+        Self(bitset)
+    }
+
+    pub fn new_all_used() -> Self {
+        Self(FiniteBitSet::new_empty())
+    }
+
+    pub fn mark_used(&mut self, idx: u32) {
+        self.0.clear(idx);
+    }
+
+    pub fn is_unused(&self, idx: u32) -> bool {
+        self.0.contains(idx).unwrap_or(false)
+    }
+
+    pub fn is_used(&self, idx: u32) -> bool {
+        !self.is_unused(idx)
+    }
+
+    pub fn all_used(&self) -> bool {
+        self.0.is_empty()
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f01d74539a1..fa571d480b6 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -86,7 +86,7 @@ pub use self::context::{
     tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
     TyCtxtFeed,
 };
-pub use self::instance::{Instance, InstanceDef, ShortInstance};
+pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
 pub use self::list::List;
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::rvalue_scopes::RvalueScopes;
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index a21e3961cb6..72f45198579 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -60,6 +60,7 @@ trivially_parameterized_over_tcx! {
     ty::ImplPolarity,
     ty::ReprOptions,
     ty::TraitDef,
+    ty::UnusedGenericParams,
     ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
     ty::fast_reject::SimplifiedType,
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 642900d3ab4..9d4ee22a727 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -34,7 +34,7 @@ use crate::ty::layout::TyAndLayout;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::GeneratorDiagnosticData;
-use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams};
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_attr as attr;
@@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::hir_id::OwnerId;
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
-use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use rustc_session::cstore::{CrateDepKind, CrateSource};
 use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index aa3227cac2d..5233cfb2120 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -32,13 +32,13 @@ pub struct TypeLengthLimit {
     pub type_length: usize,
 }
 
-pub struct UnusedGenericParams {
+pub struct UnusedGenericParamsHint {
     pub span: Span,
     pub param_spans: Vec<Span>,
     pub param_names: Vec<String>,
 }
 
-impl IntoDiagnostic<'_> for UnusedGenericParams {
+impl IntoDiagnostic<'_> for UnusedGenericParamsHint {
     #[track_caller]
     fn into_diagnostic(
         self,
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 703ed09a254..c8fc69eb856 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -6,7 +6,6 @@
 //! for their size, offset of a field, etc.).
 
 use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
-use rustc_index::bit_set::FiniteBitSet;
 use rustc_middle::mir::{
     self,
     visit::{TyContext, Visitor},
@@ -17,12 +16,12 @@ use rustc_middle::ty::{
     query::Providers,
     subst::SubstsRef,
     visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-    Const, Ty, TyCtxt,
+    Const, Ty, TyCtxt, UnusedGenericParams,
 };
 use rustc_span::symbol::sym;
 use std::ops::ControlFlow;
 
-use crate::errors::UnusedGenericParams;
+use crate::errors::UnusedGenericParamsHint;
 
 /// Provide implementations of queries relating to polymorphization analysis.
 pub fn provide(providers: &mut Providers) {
@@ -36,16 +35,16 @@ pub fn provide(providers: &mut Providers) {
 fn unused_generic_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
-) -> FiniteBitSet<u32> {
+) -> UnusedGenericParams {
     if !tcx.sess.opts.unstable_opts.polymorphize {
         // If polymorphization disabled, then all parameters are used.
-        return FiniteBitSet::new_empty();
+        return UnusedGenericParams::new_all_used();
     }
 
     let def_id = instance.def_id();
     // Exit early if this instance should not be polymorphized.
     if !should_polymorphize(tcx, def_id, instance) {
-        return FiniteBitSet::new_empty();
+        return UnusedGenericParams::new_all_used();
     }
 
     let generics = tcx.generics_of(def_id);
@@ -53,14 +52,13 @@ fn unused_generic_params<'tcx>(
 
     // Exit early when there are no parameters to be unused.
     if generics.count() == 0 {
-        return FiniteBitSet::new_empty();
+        return UnusedGenericParams::new_all_used();
     }
 
     // Create a bitset with N rightmost ones for each parameter.
     let generics_count: u32 =
         generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
-    let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
-    unused_parameters.set_range(0..generics_count);
+    let mut unused_parameters = UnusedGenericParams::new_all_unused(generics_count);
     debug!(?unused_parameters, "(start)");
 
     mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
@@ -78,7 +76,7 @@ fn unused_generic_params<'tcx>(
     debug!(?unused_parameters, "(end)");
 
     // Emit errors for debugging and testing if enabled.
-    if !unused_parameters.is_empty() {
+    if !unused_parameters.all_used() {
         emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
     }
 
@@ -136,13 +134,13 @@ fn mark_used_by_default_parameters<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     generics: &'tcx ty::Generics,
-    unused_parameters: &mut FiniteBitSet<u32>,
+    unused_parameters: &mut UnusedGenericParams,
 ) {
     match tcx.def_kind(def_id) {
         DefKind::Closure | DefKind::Generator => {
             for param in &generics.params {
                 debug!(?param, "(closure/gen)");
-                unused_parameters.clear(param.index);
+                unused_parameters.mark_used(param.index);
             }
         }
         DefKind::Mod
@@ -178,7 +176,7 @@ fn mark_used_by_default_parameters<'tcx>(
             for param in &generics.params {
                 debug!(?param, "(other)");
                 if let ty::GenericParamDefKind::Lifetime = param.kind {
-                    unused_parameters.clear(param.index);
+                    unused_parameters.mark_used(param.index);
                 }
             }
         }
@@ -196,7 +194,7 @@ fn emit_unused_generic_params_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     generics: &'tcx ty::Generics,
-    unused_parameters: &FiniteBitSet<u32>,
+    unused_parameters: &UnusedGenericParams,
 ) {
     let base_def_id = tcx.typeck_root_def_id(def_id);
     if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
@@ -213,7 +211,7 @@ fn emit_unused_generic_params_error<'tcx>(
     let mut next_generics = Some(generics);
     while let Some(generics) = next_generics {
         for param in &generics.params {
-            if unused_parameters.contains(param.index).unwrap_or(false) {
+            if unused_parameters.is_unused(param.index) {
                 debug!(?param);
                 let def_span = tcx.def_span(param.def_id);
                 param_spans.push(def_span);
@@ -224,14 +222,14 @@ fn emit_unused_generic_params_error<'tcx>(
         next_generics = generics.parent.map(|did| tcx.generics_of(did));
     }
 
-    tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names });
+    tcx.sess.emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
 }
 
 /// Visitor used to aggregate generic parameter uses.
 struct MarkUsedGenericParams<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
-    unused_parameters: &'a mut FiniteBitSet<u32>,
+    unused_parameters: &'a mut UnusedGenericParams,
 }
 
 impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
@@ -244,7 +242,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
         debug!(?self.unused_parameters, ?unused);
         for (i, arg) in substs.iter().enumerate() {
             let i = i.try_into().unwrap();
-            if !unused.contains(i).unwrap_or(false) {
+            if unused.is_used(i) {
                 arg.visit_with(self);
             }
         }
@@ -308,7 +306,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         match c.kind() {
             ty::ConstKind::Param(param) => {
                 debug!(?param);
-                self.unused_parameters.clear(param.index);
+                self.unused_parameters.mark_used(param.index);
                 ControlFlow::CONTINUE
             }
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
@@ -342,55 +340,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
             }
             ty::Param(param) => {
                 debug!(?param);
-                self.unused_parameters.clear(param.index);
+                self.unused_parameters.mark_used(param.index);
                 ControlFlow::CONTINUE
             }
             _ => ty.super_visit_with(self),
         }
     }
 }
-
-/// Visitor used to check if a generic parameter is used.
-struct HasUsedGenericParams<'a> {
-    unused_parameters: &'a FiniteBitSet<u32>,
-}
-
-impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
-    type BreakTy = ();
-
-    #[instrument(level = "debug", skip(self))]
-    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !c.has_non_region_param() {
-            return ControlFlow::CONTINUE;
-        }
-
-        match c.kind() {
-            ty::ConstKind::Param(param) => {
-                if self.unused_parameters.contains(param.index).unwrap_or(false) {
-                    ControlFlow::CONTINUE
-                } else {
-                    ControlFlow::BREAK
-                }
-            }
-            _ => c.super_visit_with(self),
-        }
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !ty.has_non_region_param() {
-            return ControlFlow::CONTINUE;
-        }
-
-        match ty.kind() {
-            ty::Param(param) => {
-                if self.unused_parameters.contains(param.index).unwrap_or(false) {
-                    ControlFlow::CONTINUE
-                } else {
-                    ControlFlow::BREAK
-                }
-            }
-            _ => ty.super_visit_with(self),
-        }
-    }
-}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 4c236067688..b062b43873b 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1570,7 +1570,7 @@ options! {
     /// o/w tests have closure@path
     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
         "exclude spans when debug-printing compiler state (default: no)"),
-    split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
+    split_dwarf_inlining: bool = (false, parse_bool, [TRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
     split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index b50f42c4d94..3d649bea19d 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -131,8 +131,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             else {
                 return
             };
-
-            let nested_goals = obligations.into_iter().map(|o| o.into()).collect();
+            let where_clause_bounds = tcx
+                .predicates_of(impl_def_id)
+                .instantiate(tcx, impl_substs)
+                .predicates
+                .into_iter()
+                .map(|pred| goal.with(tcx, pred));
+
+            let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect();
             let Ok(trait_ref_certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
 
             let Some(assoc_def) = fetch_eligible_assoc_item_def(
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 10b45a77dab..c69cc39acb5 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -71,7 +71,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
     ) {
-        let impl_trait_ref = acx.cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+        let tcx = acx.cx.tcx;
+
+        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
         if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
@@ -81,7 +83,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
         acx.infcx.probe(|_| {
             let impl_substs = acx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
-            let impl_trait_ref = impl_trait_ref.subst(acx.cx.tcx, impl_substs);
+            let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
             let Ok(InferOk { obligations, .. }) = acx
                 .infcx
@@ -92,8 +94,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             else {
                 return
             };
-
-            let nested_goals = obligations.into_iter().map(|o| o.into()).collect();
+            let where_clause_bounds = tcx
+                .predicates_of(impl_def_id)
+                .instantiate(tcx, impl_substs)
+                .predicates
+                .into_iter()
+                .map(|pred| goal.with(tcx, pred));
+
+            let nested_goals =
+                obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect();
 
             let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
             acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty);
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index a05128de471..2975c81f8fe 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -174,6 +174,32 @@ fn div() {
 }
 
 #[test]
+fn div_duration_f32() {
+    assert_eq!(Duration::ZERO.div_duration_f32(Duration::MAX), 0.0);
+    assert_eq!(Duration::MAX.div_duration_f32(Duration::ZERO), f32::INFINITY);
+    assert_eq!((Duration::SECOND * 2).div_duration_f32(Duration::SECOND), 2.0);
+    assert!(Duration::ZERO.div_duration_f32(Duration::ZERO).is_nan());
+    // These tests demonstrate it doesn't panic with extreme values.
+    // Accuracy of the computed value is not a huge concern, we know floats don't work well
+    // at these extremes.
+    assert!((Duration::MAX).div_duration_f32(Duration::NANOSECOND) > 10.0f32.powf(28.0));
+    assert!((Duration::NANOSECOND).div_duration_f32(Duration::MAX) < 0.1);
+}
+
+#[test]
+fn div_duration_f64() {
+    assert_eq!(Duration::ZERO.div_duration_f64(Duration::MAX), 0.0);
+    assert_eq!(Duration::MAX.div_duration_f64(Duration::ZERO), f64::INFINITY);
+    assert_eq!((Duration::SECOND * 2).div_duration_f64(Duration::SECOND), 2.0);
+    assert!(Duration::ZERO.div_duration_f64(Duration::ZERO).is_nan());
+    // These tests demonstrate it doesn't panic with extreme values.
+    // Accuracy of the computed value is not a huge concern, we know floats don't work well
+    // at these extremes.
+    assert!((Duration::MAX).div_duration_f64(Duration::NANOSECOND) > 10.0f64.powf(28.0));
+    assert!((Duration::NANOSECOND).div_duration_f64(Duration::MAX) < 0.1);
+}
+
+#[test]
 fn checked_div() {
     assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
     assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index f357d505fe8..5c5ef0b1125 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -249,8 +249,9 @@ pub struct DirBuilder {
 pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
     fn inner(path: &Path) -> io::Result<Vec<u8>> {
         let mut file = File::open(path)?;
-        let mut bytes = Vec::new();
-        file.read_to_end(&mut bytes)?;
+        let size = file.metadata().map(|m| m.len()).unwrap_or(0);
+        let mut bytes = Vec::with_capacity(size as usize);
+        io::default_read_to_end(&mut file, &mut bytes)?;
         Ok(bytes)
     }
     inner(path.as_ref())
@@ -288,8 +289,9 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
 pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
     fn inner(path: &Path) -> io::Result<String> {
         let mut file = File::open(path)?;
-        let mut string = String::new();
-        file.read_to_string(&mut string)?;
+        let size = file.metadata().map(|m| m.len()).unwrap_or(0);
+        let mut string = String::with_capacity(size as usize);
+        io::default_read_to_string(&mut file, &mut string)?;
         Ok(string)
     }
     inner(path.as_ref())
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 5aa4f238b2d..7158355ffda 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -156,7 +156,9 @@ impl Emitter for BufferEmitter {
         let mut buffer = self.buffer.borrow_mut();
 
         let fluent_args = to_fluent_args(diag.args());
-        let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
+        let translated_main_message = self
+            .translate_message(&diag.message[0].0, &fluent_args)
+            .unwrap_or_else(|e| panic!("{e}"));
 
         buffer.messages.push(format!("error from rustc: {}", translated_main_message));
         if diag.is_error() {
diff --git a/triagebot.toml b/triagebot.toml
index a3eec63e368..1f1b1f1110d 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -249,6 +249,11 @@ trigger_files = [
 [autolabel."S-waiting-on-review"]
 new_pr = true
 
+[autolabel."WG-trait-system-refactor"]
+trigger_files = [
+    "compiler/rustc_trait_selection/solve"
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"
@@ -344,7 +349,7 @@ cc = ["@BoxyUwU"]
 
 [mentions."compiler/rustc_trait_selection/src/solve/"]
 message = "Some changes occurred to the core trait solver"
-cc = ["@lcnr", "@compiler-errors"]
+cc = ["@rust-lang/initiative-trait-system-refactor"]
 
 [mentions."compiler/rustc_trait_selection/src/traits/engine.rs"]
 message = """