about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-10-12 16:39:36 +0000
committerbors <bors@rust-lang.org>2023-10-12 16:39:36 +0000
commit672fad9b860c6f2e2b5ca088d7b426099c7198a5 (patch)
treef38cb8b5af545a9736996988cc07c5ca4f9534c0
parent19149d1ea92f79874420f9268d891b11a79e1eec (diff)
parent6ccc52126785c08c1c00a9447b91573fb83f6a9c (diff)
downloadrust-672fad9b860c6f2e2b5ca088d7b426099c7198a5.tar.gz
rust-672fad9b860c6f2e2b5ca088d7b426099c7198a5.zip
Auto merge of #116671 - matthiaskrgr:rollup-b41rw92, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #116593 (Add unstable book page for the no-jump-tables codegen option)
 - #116625 (`rustc_hir_pretty` cleanups)
 - #116642 (Handle several `#[diagnostic::on_unimplemented]` attributes correctly)
 - #116654 (coverage: Clarify loop-edge detection and graph traversal)
 - #116669 (Fix mips platform support entries.)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs191
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs131
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs161
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs46
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/no-jump-tables.md19
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs22
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr52
12 files changed, 335 insertions, 309 deletions
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 8587b009f25..ab6ab391484 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -52,8 +52,6 @@ pub struct NoAnn;
 impl PpAnn for NoAnn {}
 pub const NO_ANN: &dyn PpAnn = &NoAnn;
 
-/// Identical to the `PpAnn` implementation for `hir::Crate`,
-/// except it avoids creating a dependency on the whole crate.
 impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
@@ -75,7 +73,11 @@ pub struct State<'a> {
 }
 
 impl<'a> State<'a> {
-    pub fn print_node(&mut self, node: Node<'_>) {
+    fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
+        (self.attrs)(id)
+    }
+
+    fn print_node(&mut self, node: Node<'_>) {
         match node {
             Node::Param(a) => self.print_param(a),
             Node::Item(a) => self.print_item(a),
@@ -144,7 +146,7 @@ impl<'a> PrintState<'a> for State<'a> {
     }
 }
 
-pub const INDENT_UNIT: isize = 4;
+const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
@@ -156,7 +158,12 @@ pub fn print_crate<'a>(
     attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
     ann: &'a dyn PpAnn,
 ) -> String {
-    let mut s = State::new_from_input(sm, filename, input, attrs, ann);
+    let mut s = State {
+        s: pp::Printer::new(),
+        comments: Some(Comments::new(sm, filename, input)),
+        attrs,
+        ann,
+    };
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
@@ -166,28 +173,7 @@ pub fn print_crate<'a>(
     s.s.eof()
 }
 
-impl<'a> State<'a> {
-    pub fn new_from_input(
-        sm: &'a SourceMap,
-        filename: FileName,
-        input: String,
-        attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
-        ann: &'a dyn PpAnn,
-    ) -> State<'a> {
-        State {
-            s: pp::Printer::new(),
-            comments: Some(Comments::new(sm, filename, input)),
-            attrs,
-            ann,
-        }
-    }
-
-    fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
-        (self.attrs)(id)
-    }
-}
-
-pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
+fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
 where
     F: FnOnce(&mut State<'_>),
 {
@@ -196,52 +182,20 @@ where
     printer.s.eof()
 }
 
-pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String {
-    to_string(NO_ANN, |s| s.print_generic_params(generic_params))
-}
-
-pub fn bounds_to_string<'b>(bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>) -> String {
-    to_string(NO_ANN, |s| s.print_bounds("", bounds))
-}
-
 pub fn ty_to_string(ty: &hir::Ty<'_>) -> String {
     to_string(NO_ANN, |s| s.print_type(ty))
 }
 
-pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String {
-    to_string(NO_ANN, |s| s.print_path_segment(segment))
-}
-
-pub fn path_to_string(segment: &hir::Path<'_>) -> String {
-    to_string(NO_ANN, |s| s.print_path(segment, false))
-}
-
 pub fn qpath_to_string(segment: &hir::QPath<'_>) -> String {
     to_string(NO_ANN, |s| s.print_qpath(segment, false))
 }
 
-pub fn fn_to_string(
-    decl: &hir::FnDecl<'_>,
-    header: hir::FnHeader,
-    name: Option<Symbol>,
-    generics: &hir::Generics<'_>,
-    arg_names: &[Ident],
-    body_id: Option<hir::BodyId>,
-) -> String {
-    to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id))
-}
-
-pub fn enum_def_to_string(
-    enum_definition: &hir::EnumDef<'_>,
-    generics: &hir::Generics<'_>,
-    name: Symbol,
-    span: rustc_span::Span,
-) -> String {
-    to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span))
+pub fn pat_to_string(pat: &hir::Pat<'_>) -> String {
+    to_string(NO_ANN, |s| s.print_pat(pat))
 }
 
 impl<'a> State<'a> {
-    pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
+    fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
         self.maybe_print_comment(span.hi());
         self.break_offset_if_not_bol(1, -INDENT_UNIT);
         self.word("}");
@@ -250,11 +204,11 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn bclose(&mut self, span: rustc_span::Span) {
+    fn bclose(&mut self, span: rustc_span::Span) {
         self.bclose_maybe_open(span, true)
     }
 
-    pub fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
+    fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
     where
         F: FnMut(&mut State<'_>, &T),
         G: FnMut(&T) -> rustc_span::Span,
@@ -275,25 +229,25 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
+    fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
     }
 
-    pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
+    fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
         self.print_inner_attributes(attrs);
         for &item_id in _mod.item_ids {
             self.ann.nested(self, Nested::Item(item_id));
         }
     }
 
-    pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
+    fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
         if !lifetime.is_elided() {
             self.print_lifetime(lifetime);
             self.nbsp();
         }
     }
 
-    pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
+    fn print_type(&mut self, ty: &hir::Ty<'_>) {
         self.maybe_print_comment(ty.span.lo());
         self.ibox(0);
         match ty.kind {
@@ -371,7 +325,7 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
+    fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
         self.print_outer_attributes(self.attrs(item.hir_id()));
@@ -478,8 +432,7 @@ impl<'a> State<'a> {
         self.end(); // end the outer ibox
     }
 
-    /// Pretty-print an item
-    pub fn print_item(&mut self, item: &hir::Item<'_>) {
+    fn print_item(&mut self, item: &hir::Item<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
         let attrs = self.attrs(item.hir_id());
@@ -704,7 +657,7 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::Item(item))
     }
 
-    pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
+    fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
         self.print_path(t.path, false);
     }
 
@@ -721,7 +674,7 @@ impl<'a> State<'a> {
         self.print_trait_ref(&t.trait_ref);
     }
 
-    pub fn print_enum_def(
+    fn print_enum_def(
         &mut self,
         enum_definition: &hir::EnumDef<'_>,
         generics: &hir::Generics<'_>,
@@ -736,7 +689,7 @@ impl<'a> State<'a> {
         self.print_variants(enum_definition.variants, span);
     }
 
-    pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
+    fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
         self.bopen();
         for v in variants {
             self.space_if_not_bol();
@@ -751,14 +704,14 @@ impl<'a> State<'a> {
         self.bclose(span)
     }
 
-    pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
+    fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
         match defaultness {
             hir::Defaultness::Default { .. } => self.word_nbsp("default"),
             hir::Defaultness::Final => (),
         }
     }
 
-    pub fn print_struct(
+    fn print_struct(
         &mut self,
         struct_def: &hir::VariantData<'_>,
         generics: &hir::Generics<'_>,
@@ -807,7 +760,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
+    fn print_variant(&mut self, v: &hir::Variant<'_>) {
         self.head("");
         let generics = hir::Generics::empty();
         self.print_struct(&v.data, generics, v.ident.name, v.span, false);
@@ -817,7 +770,8 @@ impl<'a> State<'a> {
             self.print_anon_const(d);
         }
     }
-    pub fn print_method_sig(
+
+    fn print_method_sig(
         &mut self,
         ident: Ident,
         m: &hir::FnSig<'_>,
@@ -828,7 +782,7 @@ impl<'a> State<'a> {
         self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id);
     }
 
-    pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
+    fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
         self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ti.span.lo());
@@ -856,7 +810,7 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::SubItem(ti.hir_id()))
     }
 
-    pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
+    fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
         self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ii.span.lo());
@@ -881,7 +835,7 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
     }
 
-    pub fn print_local(
+    fn print_local(
         &mut self,
         init: Option<&hir::Expr<'_>>,
         els: Option<&hir::Block<'_>>,
@@ -914,7 +868,7 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
+    fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
             hir::StmtKind::Local(loc) => {
@@ -937,19 +891,19 @@ impl<'a> State<'a> {
         self.maybe_print_trailing_comment(st.span, None)
     }
 
-    pub fn print_block(&mut self, blk: &hir::Block<'_>) {
+    fn print_block(&mut self, blk: &hir::Block<'_>) {
         self.print_block_with_attrs(blk, &[])
     }
 
-    pub fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) {
+    fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) {
         self.print_block_maybe_unclosed(blk, &[], false)
     }
 
-    pub fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) {
+    fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) {
         self.print_block_maybe_unclosed(blk, attrs, true)
     }
 
-    pub fn print_block_maybe_unclosed(
+    fn print_block_maybe_unclosed(
         &mut self,
         blk: &hir::Block<'_>,
         attrs: &[ast::Attribute],
@@ -1005,7 +959,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_if(
+    fn print_if(
         &mut self,
         test: &hir::Expr<'_>,
         blk: &hir::Expr<'_>,
@@ -1018,14 +972,14 @@ impl<'a> State<'a> {
         self.print_else(elseopt)
     }
 
-    pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+    fn print_array_length(&mut self, len: &hir::ArrayLen) {
         match len {
             hir::ArrayLen::Infer(_, _) => self.word("_"),
             hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
         }
     }
 
-    pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
+    fn print_anon_const(&mut self, constant: &hir::AnonConst) {
         self.ann.nested(self, Nested::Body(constant.body))
     }
 
@@ -1041,7 +995,7 @@ impl<'a> State<'a> {
 
     /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
     /// `if cond { ... }`.
-    pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
+    fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
     }
 
@@ -1360,7 +1314,7 @@ impl<'a> State<'a> {
         self.pclose();
     }
 
-    pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
+    fn print_expr(&mut self, expr: &hir::Expr<'_>) {
         self.maybe_print_comment(expr.span.lo());
         self.print_outer_attributes(self.attrs(expr.hir_id));
         self.ibox(INDENT_UNIT);
@@ -1593,7 +1547,7 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
+    fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
         self.print_pat(loc.pat);
         if let Some(ty) = loc.ty {
             self.word_space(":");
@@ -1601,11 +1555,11 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_name(&mut self, name: Symbol) {
+    fn print_name(&mut self, name: Symbol) {
         self.print_ident(Ident::with_dummy_span(name))
     }
 
-    pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
+    fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
         self.maybe_print_comment(path.span.lo());
 
         for (i, segment) in path.segments.iter().enumerate() {
@@ -1619,14 +1573,14 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
+    fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
         if segment.ident.name != kw::PathRoot {
             self.print_ident(segment.ident);
             self.print_generic_args(segment.args(), false);
         }
     }
 
-    pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
+    fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
         match *qpath {
             hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params),
             hir::QPath::Resolved(Some(qself), path) => {
@@ -1743,7 +1697,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
+    fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
         self.print_ident(binding.ident);
         self.print_generic_args(binding.gen_args, false);
         self.space();
@@ -1761,7 +1715,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
+    fn print_pat(&mut self, pat: &hir::Pat<'_>) {
         self.maybe_print_comment(pat.span.lo());
         self.ann.pre(self, AnnNode::Pat(pat));
         // Pat isn't normalized, but the beauty of it
@@ -1905,7 +1859,7 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::Pat(pat))
     }
 
-    pub fn print_patfield(&mut self, field: &hir::PatField<'_>) {
+    fn print_patfield(&mut self, field: &hir::PatField<'_>) {
         if self.attrs(field.hir_id).is_empty() {
             self.space();
         }
@@ -1919,12 +1873,12 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    pub fn print_param(&mut self, arg: &hir::Param<'_>) {
+    fn print_param(&mut self, arg: &hir::Param<'_>) {
         self.print_outer_attributes(self.attrs(arg.hir_id));
         self.print_pat(arg.pat);
     }
 
-    pub fn print_arm(&mut self, arm: &hir::Arm<'_>) {
+    fn print_arm(&mut self, arm: &hir::Arm<'_>) {
         // I have no idea why this check is necessary, but here it
         // is :(
         if self.attrs(arm.hir_id).is_empty() {
@@ -1976,7 +1930,7 @@ impl<'a> State<'a> {
         self.end() // close enclosing cbox
     }
 
-    pub fn print_fn(
+    fn print_fn(
         &mut self,
         decl: &hir::FnDecl<'_>,
         header: hir::FnHeader,
@@ -2056,14 +2010,14 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
+    fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
         match capture_clause {
             hir::CaptureBy::Value => self.word_space("move"),
             hir::CaptureBy::Ref => {}
         }
     }
 
-    pub fn print_closure_binder(
+    fn print_closure_binder(
         &mut self,
         binder: hir::ClosureBinder,
         generic_params: &[GenericParam<'_>],
@@ -2083,7 +2037,8 @@ impl<'a> State<'a> {
 
         match binder {
             hir::ClosureBinder::Default => {}
-            // we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions
+            // We need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional
+            // restrictions.
             hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
             hir::ClosureBinder::For { .. } => {
                 self.word("for");
@@ -2099,7 +2054,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_bounds<'b>(
+    fn print_bounds<'b>(
         &mut self,
         prefix: &'static str,
         bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>,
@@ -2137,7 +2092,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
+    fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
         if !generic_params.is_empty() {
             self.word("<");
 
@@ -2147,7 +2102,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_generic_param(&mut self, param: &GenericParam<'_>) {
+    fn print_generic_param(&mut self, param: &GenericParam<'_>) {
         if let GenericParamKind::Const { .. } = param.kind {
             self.word_space("const");
         }
@@ -2175,11 +2130,11 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
+    fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
         self.print_ident(lifetime.ident)
     }
 
-    pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
+    fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
         if generics.predicates.is_empty() {
             return;
         }
@@ -2236,7 +2191,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
+    fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
         match mutbl {
             hir::Mutability::Mut => self.word_nbsp("mut"),
             hir::Mutability::Not => {
@@ -2247,12 +2202,12 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
+    fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
         self.print_mutability(mt.mutbl, print_const);
         self.print_type(mt.ty);
     }
 
-    pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
+    fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
         if let hir::FnRetTy::DefaultReturn(..) = decl.output {
             return;
         }
@@ -2271,7 +2226,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_ty_fn(
+    fn print_ty_fn(
         &mut self,
         abi: Abi,
         unsafety: hir::Unsafety,
@@ -2299,7 +2254,7 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
+    fn print_fn_header_info(&mut self, header: hir::FnHeader) {
         self.print_constness(header.constness);
 
         match header.asyncness {
@@ -2317,21 +2272,21 @@ impl<'a> State<'a> {
         self.word("fn")
     }
 
-    pub fn print_constness(&mut self, s: hir::Constness) {
+    fn print_constness(&mut self, s: hir::Constness) {
         match s {
             hir::Constness::NotConst => {}
             hir::Constness::Const => self.word_nbsp("const"),
         }
     }
 
-    pub fn print_unsafety(&mut self, s: hir::Unsafety) {
+    fn print_unsafety(&mut self, s: hir::Unsafety) {
         match s {
             hir::Unsafety::Normal => {}
             hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
         }
     }
 
-    pub fn print_is_auto(&mut self, s: hir::IsAuto) {
+    fn print_is_auto(&mut self, s: hir::IsAuto) {
         match s {
             hir::IsAuto::Yes => self.word_nbsp("auto"),
             hir::IsAuto::No => {}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 3f9c9b3381b..072c7a9f36a 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1504,9 +1504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
             if has_shorthand_field_name {
-                let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
-                    s.print_qpath(qpath, false)
-                });
+                let path = rustc_hir_pretty::qpath_to_string(qpath);
                 let mut err = struct_span_err!(
                     self.tcx.sess,
                     pat.span,
@@ -1688,9 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return None;
             }
 
-            let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
-                s.print_qpath(qpath, false)
-            });
+            let path = rustc_hir_pretty::qpath_to_string(qpath);
             let mut err = struct_span_err!(
                 self.tcx.sess,
                 pat.span,
@@ -1740,9 +1736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             f
                         }
                     }
-                    Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
-                        s.print_pat(field.pat)
-                    }),
+                    Err(_) => rustc_hir_pretty::pat_to_string(field.pat),
                 }
             })
             .collect::<Vec<String>>()
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 78845af0162..77e3dee1fef 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -245,13 +245,13 @@ impl<'a> MakeBcbCounters<'a> {
         // the loop. The `traversal` state includes a `context_stack`, providing a way to know if
         // the current BCB is in one or more nested loops or not.
         let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks);
-        while let Some(bcb) = traversal.next(self.basic_coverage_blocks) {
+        while let Some(bcb) = traversal.next() {
             if bcb_has_coverage_spans(bcb) {
                 debug!("{:?} has at least one coverage span. Get or make its counter", bcb);
                 let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
 
                 if self.bcb_needs_branch_counters(bcb) {
-                    self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?;
+                    self.make_branch_counters(&traversal, bcb, branching_counter_operand)?;
                 }
             } else {
                 debug!(
@@ -274,7 +274,7 @@ impl<'a> MakeBcbCounters<'a> {
 
     fn make_branch_counters(
         &mut self,
-        traversal: &mut TraverseCoverageGraphWithLoops,
+        traversal: &TraverseCoverageGraphWithLoops<'_>,
         branching_bcb: BasicCoverageBlock,
         branching_counter_operand: Operand,
     ) -> Result<(), Error> {
@@ -507,21 +507,14 @@ impl<'a> MakeBcbCounters<'a> {
     /// found, select any branch.
     fn choose_preferred_expression_branch(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops,
+        traversal: &TraverseCoverageGraphWithLoops<'_>,
         branches: &[BcbBranch],
     ) -> BcbBranch {
-        let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
-
-        let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches);
-        if let Some(reloop_branch_without_counter) =
-            some_reloop_branch.filter(branch_needs_a_counter)
-        {
-            debug!(
-                "Selecting reloop_branch={:?} that still needs a counter, to get the \
-                `Expression`",
-                reloop_branch_without_counter
-            );
-            reloop_branch_without_counter
+        let good_reloop_branch = self.find_good_reloop_branch(traversal, &branches);
+        if let Some(reloop_branch) = good_reloop_branch {
+            assert!(self.branch_has_no_counter(&reloop_branch));
+            debug!("Selecting reloop branch {reloop_branch:?} to get an expression");
+            reloop_branch
         } else {
             let &branch_without_counter =
                 branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect(
@@ -538,75 +531,52 @@ impl<'a> MakeBcbCounters<'a> {
         }
     }
 
-    /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has
-    /// multiple incoming edges) can have a counter computed by expression.
-    ///
-    /// If at least one of the branches leads outside of a loop (`found_loop_exit` is
-    /// true), and at least one other branch does not exit the loop (the first of which
-    /// is captured in `some_reloop_branch`), it's likely any reloop branch will be
-    /// executed far more often than loop exit branch, making the reloop branch a better
-    /// candidate for an expression.
-    fn find_some_reloop_branch(
+    /// Tries to find a branch that leads back to the top of a loop, and that
+    /// doesn't already have a counter. Such branches are good candidates to
+    /// be given an expression (instead of a physical counter), because they
+    /// will tend to be executed more times than a loop-exit branch.
+    fn find_good_reloop_branch(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops,
+        traversal: &TraverseCoverageGraphWithLoops<'_>,
         branches: &[BcbBranch],
     ) -> Option<BcbBranch> {
-        let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
-
-        let mut some_reloop_branch: Option<BcbBranch> = None;
-        for context in traversal.context_stack.iter().rev() {
-            if let Some((backedge_from_bcbs, _)) = &context.loop_backedges {
-                let mut found_loop_exit = false;
-                for &branch in branches.iter() {
-                    if backedge_from_bcbs.iter().any(|&backedge_from_bcb| {
-                        self.bcb_dominates(branch.target_bcb, backedge_from_bcb)
-                    }) {
-                        if let Some(reloop_branch) = some_reloop_branch {
-                            if self.branch_has_no_counter(&reloop_branch) {
-                                // we already found a candidate reloop_branch that still
-                                // needs a counter
-                                continue;
-                            }
-                        }
-                        // The path from branch leads back to the top of the loop. Set this
-                        // branch as the `reloop_branch`. If this branch already has a
-                        // counter, and we find another reloop branch that doesn't have a
-                        // counter yet, that branch will be selected as the `reloop_branch`
-                        // instead.
-                        some_reloop_branch = Some(branch);
-                    } else {
-                        // The path from branch leads outside this loop
-                        found_loop_exit = true;
-                    }
-                    if found_loop_exit
-                        && some_reloop_branch.filter(branch_needs_a_counter).is_some()
-                    {
-                        // Found both a branch that exits the loop and a branch that returns
-                        // to the top of the loop (`reloop_branch`), and the `reloop_branch`
-                        // doesn't already have a counter.
-                        break;
+        // Consider each loop on the current traversal context stack, top-down.
+        for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
+            let mut all_branches_exit_this_loop = true;
+
+            // Try to find a branch that doesn't exit this loop and doesn't
+            // already have a counter.
+            for &branch in branches {
+                // A branch is a reloop branch if it dominates any BCB that has
+                // an edge back to the loop header. (Other branches are exits.)
+                let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| {
+                    self.basic_coverage_blocks.dominates(branch.target_bcb, reloop_bcb)
+                });
+
+                if is_reloop_branch {
+                    all_branches_exit_this_loop = false;
+                    if self.branch_has_no_counter(&branch) {
+                        // We found a good branch to be given an expression.
+                        return Some(branch);
                     }
+                    // Keep looking for another reloop branch without a counter.
+                } else {
+                    // This branch exits the loop.
                 }
-                if !found_loop_exit {
-                    debug!(
-                        "No branches exit the loop, so any branch without an existing \
-                        counter can have the `Expression`."
-                    );
-                    break;
-                }
-                if some_reloop_branch.is_some() {
-                    debug!(
-                        "Found a branch that exits the loop and a branch the loops back to \
-                        the top of the loop (`reloop_branch`). The `reloop_branch` will \
-                        get the `Expression`, as long as it still needs a counter."
-                    );
-                    break;
-                }
-                // else all branches exited this loop context, so run the same checks with
-                // the outer loop(s)
             }
+
+            if !all_branches_exit_this_loop {
+                // We found one or more reloop branches, but all of them already
+                // have counters. Let the caller choose one of the exit branches.
+                debug!("All reloop branches had counters; skip checking the other loops");
+                return None;
+            }
+
+            // All of the branches exit this loop, so keep looking for a good
+            // reloop branch for one of the outer loops.
         }
-        some_reloop_branch
+
+        None
     }
 
     #[inline]
@@ -652,9 +622,4 @@ impl<'a> MakeBcbCounters<'a> {
     fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool {
         self.bcb_predecessors(bcb).len() <= 1
     }
-
-    #[inline]
-    fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
-        self.basic_coverage_blocks.dominates(dom, node)
-    }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 39027d21f06..9a7adaada09 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -6,6 +6,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
 
 use std::cmp::Ordering;
+use std::collections::VecDeque;
 use std::ops::{Index, IndexMut};
 
 /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
@@ -385,57 +386,72 @@ fn bcb_filtered_successors<'a, 'tcx>(
 /// ensures a loop is completely traversed before processing Blocks after the end of the loop.
 #[derive(Debug)]
 pub(super) struct TraversalContext {
-    /// From one or more backedges returning to a loop header.
-    pub loop_backedges: Option<(Vec<BasicCoverageBlock>, BasicCoverageBlock)>,
-
-    /// worklist, to be traversed, of CoverageGraph in the loop with the given loop
-    /// backedges, such that the loop is the inner inner-most loop containing these
-    /// CoverageGraph
-    pub worklist: Vec<BasicCoverageBlock>,
+    /// BCB with one or more incoming loop backedges, indicating which loop
+    /// this context is for.
+    ///
+    /// If `None`, this is the non-loop context for the function as a whole.
+    loop_header: Option<BasicCoverageBlock>,
+
+    /// Worklist of BCBs to be processed in this context.
+    worklist: VecDeque<BasicCoverageBlock>,
 }
 
-pub(super) struct TraverseCoverageGraphWithLoops {
-    pub backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
-    pub context_stack: Vec<TraversalContext>,
+pub(super) struct TraverseCoverageGraphWithLoops<'a> {
+    basic_coverage_blocks: &'a CoverageGraph,
+
+    backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
+    context_stack: Vec<TraversalContext>,
     visited: BitSet<BasicCoverageBlock>,
 }
 
-impl TraverseCoverageGraphWithLoops {
-    pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
-        let start_bcb = basic_coverage_blocks.start_node();
+impl<'a> TraverseCoverageGraphWithLoops<'a> {
+    pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
         let backedges = find_loop_backedges(basic_coverage_blocks);
-        let context_stack =
-            vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }];
+
+        let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
+        let context_stack = vec![TraversalContext { loop_header: None, worklist }];
+
         // `context_stack` starts with a `TraversalContext` for the main function context (beginning
         // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top
         // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
         // exhausted.
         let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        Self { backedges, context_stack, visited }
+        Self { basic_coverage_blocks, backedges, context_stack, visited }
     }
 
-    pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option<BasicCoverageBlock> {
+    /// For each loop on the loop context stack (top-down), yields a list of BCBs
+    /// within that loop that have an outgoing edge back to the loop header.
+    pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
+        self.context_stack
+            .iter()
+            .rev()
+            .filter_map(|context| context.loop_header)
+            .map(|header_bcb| self.backedges[header_bcb].as_slice())
+    }
+
+    pub(super) fn next(&mut self) -> Option<BasicCoverageBlock> {
         debug!(
             "TraverseCoverageGraphWithLoops::next - context_stack: {:?}",
             self.context_stack.iter().rev().collect::<Vec<_>>()
         );
 
         while let Some(context) = self.context_stack.last_mut() {
-            if let Some(next_bcb) = context.worklist.pop() {
-                if !self.visited.insert(next_bcb) {
-                    debug!("Already visited: {:?}", next_bcb);
+            if let Some(bcb) = context.worklist.pop_front() {
+                if !self.visited.insert(bcb) {
+                    debug!("Already visited: {bcb:?}");
                     continue;
                 }
-                debug!("Visiting {:?}", next_bcb);
-                if self.backedges[next_bcb].len() > 0 {
-                    debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb);
+                debug!("Visiting {bcb:?}");
+
+                if self.backedges[bcb].len() > 0 {
+                    debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
                     self.context_stack.push(TraversalContext {
-                        loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)),
-                        worklist: Vec::new(),
+                        loop_header: Some(bcb),
+                        worklist: VecDeque::new(),
                     });
                 }
-                self.extend_worklist(basic_coverage_blocks, next_bcb);
-                return Some(next_bcb);
+                self.add_successors_to_worklists(bcb);
+                return Some(bcb);
             } else {
                 // Strip contexts with empty worklists from the top of the stack
                 self.context_stack.pop();
@@ -445,13 +461,10 @@ impl TraverseCoverageGraphWithLoops {
         None
     }
 
-    pub fn extend_worklist(
-        &mut self,
-        basic_coverage_blocks: &CoverageGraph,
-        bcb: BasicCoverageBlock,
-    ) {
-        let successors = &basic_coverage_blocks.successors[bcb];
+    pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) {
+        let successors = &self.basic_coverage_blocks.successors[bcb];
         debug!("{:?} has {} successors:", bcb, successors.len());
+
         for &successor in successors {
             if successor == bcb {
                 debug!(
@@ -460,56 +473,44 @@ impl TraverseCoverageGraphWithLoops {
                     bcb
                 );
                 // Don't re-add this successor to the worklist. We are already processing it.
+                // FIXME: This claims to skip just the self-successor, but it actually skips
+                // all other successors as well. Does that matter?
                 break;
             }
-            for context in self.context_stack.iter_mut().rev() {
-                // Add successors of the current BCB to the appropriate context. Successors that
-                // stay within a loop are added to the BCBs context worklist. Successors that
-                // exit the loop (they are not dominated by the loop header) must be reachable
-                // from other BCBs outside the loop, and they will be added to a different
-                // worklist.
-                //
-                // Branching blocks (with more than one successor) must be processed before
-                // blocks with only one successor, to prevent unnecessarily complicating
-                // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
-                // branching block would have given an `Expression` (or vice versa).
-                let (some_successor_to_add, some_loop_header) =
-                    if let Some((_, loop_header)) = context.loop_backedges {
-                        if basic_coverage_blocks.dominates(loop_header, successor) {
-                            (Some(successor), Some(loop_header))
-                        } else {
-                            (None, None)
-                        }
-                    } else {
-                        (Some(successor), None)
-                    };
-                if let Some(successor_to_add) = some_successor_to_add {
-                    if basic_coverage_blocks.successors[successor_to_add].len() > 1 {
-                        debug!(
-                            "{:?} successor is branching. Prioritize it at the beginning of \
-                            the {}",
-                            successor_to_add,
-                            if let Some(loop_header) = some_loop_header {
-                                format!("worklist for the loop headed by {loop_header:?}")
-                            } else {
-                                String::from("non-loop worklist")
-                            },
-                        );
-                        context.worklist.insert(0, successor_to_add);
-                    } else {
-                        debug!(
-                            "{:?} successor is non-branching. Defer it to the end of the {}",
-                            successor_to_add,
-                            if let Some(loop_header) = some_loop_header {
-                                format!("worklist for the loop headed by {loop_header:?}")
-                            } else {
-                                String::from("non-loop worklist")
-                            },
-                        );
-                        context.worklist.push(successor_to_add);
+
+            // Add successors of the current BCB to the appropriate context. Successors that
+            // stay within a loop are added to the BCBs context worklist. Successors that
+            // exit the loop (they are not dominated by the loop header) must be reachable
+            // from other BCBs outside the loop, and they will be added to a different
+            // worklist.
+            //
+            // Branching blocks (with more than one successor) must be processed before
+            // blocks with only one successor, to prevent unnecessarily complicating
+            // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
+            // branching block would have given an `Expression` (or vice versa).
+
+            let context = self
+                .context_stack
+                .iter_mut()
+                .rev()
+                .find(|context| match context.loop_header {
+                    Some(loop_header) => {
+                        self.basic_coverage_blocks.dominates(loop_header, successor)
                     }
-                    break;
-                }
+                    None => true,
+                })
+                .unwrap_or_else(|| bug!("should always fall back to the root non-loop context"));
+            debug!("adding to worklist for {:?}", context.loop_header);
+
+            // FIXME: The code below had debug messages claiming to add items to a
+            // particular end of the worklist, but was confused about which end was
+            // which. The existing behaviour has been preserved for now, but it's
+            // unclear what the intended behaviour was.
+
+            if self.basic_coverage_blocks.successors[successor].len() > 1 {
+                context.worklist.push_back(successor);
+            } else {
+                context.worklist.push_front(successor);
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index ee7cb791c81..487d2282364 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -628,7 +628,7 @@ fn test_traverse_coverage_with_loops() {
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     let mut traversed_in_order = Vec::new();
     let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks);
-    while let Some(bcb) = traversal.next(&basic_coverage_blocks) {
+    while let Some(bcb) = traversal.next() {
         traversed_in_order.push(bcb);
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index d9059e46a8c..cc1f13a2f0f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -1,6 +1,6 @@
 use super::{ObligationCauseCode, PredicateObligation};
 use crate::infer::error_reporting::TypeErrCtxt;
-use rustc_ast::{MetaItem, NestedMetaItem};
+use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
@@ -474,18 +474,40 @@ impl<'tcx> OnUnimplementedDirective {
     }
 
     pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
-        let mut is_diagnostic_namespace_variant = false;
-        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| {
-            if tcx.features().diagnostic_namespace {
-                is_diagnostic_namespace_variant = true;
-                tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next()
-            } else {
-                None
-            }
-        }) else {
-            return Ok(None);
-        };
+        if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
+            return Self::parse_attribute(attr, false, tcx, item_def_id);
+        } else if tcx.features().diagnostic_namespace {
+            tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented])
+                .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose())
+                .try_fold(None, |aggr: Option<Self>, directive| {
+                    let directive = directive?;
+                    if let Some(aggr) = aggr {
+                        let mut subcommands = aggr.subcommands;
+                        subcommands.extend(directive.subcommands);
+                        Ok(Some(Self {
+                            condition: aggr.condition.or(directive.condition),
+                            subcommands,
+                            message: aggr.message.or(directive.message),
+                            label: aggr.label.or(directive.label),
+                            note: aggr.note.or(directive.note),
+                            parent_label: aggr.parent_label.or(directive.parent_label),
+                            append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
+                        }))
+                    } else {
+                        Ok(Some(directive))
+                    }
+                })
+        } else {
+            Ok(None)
+        }
+    }
 
+    fn parse_attribute(
+        attr: &Attribute,
+        is_diagnostic_namespace_variant: bool,
+        tcx: TyCtxt<'tcx>,
+        item_def_id: DefId,
+    ) -> Result<Option<Self>, ErrorGuaranteed> {
         let result = if let Some(items) = attr.meta_item_list() {
             Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
         } else if let Some(value) = attr.value_str() {
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index d25fa661c3f..1fb5e56db5d 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -286,10 +286,6 @@ target | std | host | notes
 `mipsel-unknown-linux-musl` | ✓ |  | MIPS (little endian) Linux with musl libc
 `mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 [`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * |  | MIPS (LE) Sony PlayStation 1 (PSX)
-`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
-`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
 [`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Big Endian
diff --git a/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md
new file mode 100644
index 00000000000..f096c20f4bd
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md
@@ -0,0 +1,19 @@
+# `no-jump-tables`
+
+The tracking issue for this feature is [#116592](https://github.com/rust-lang/rust/issues/116592)
+
+---
+
+This option enables the `-fno-jump-tables` flag for LLVM, which makes the
+codegen backend avoid generating jump tables when lowering switches.
+
+This option adds the LLVM `no-jump-tables=true` attribute to every function.
+
+The option can be used to help provide protection against
+jump-oriented-programming (JOP) attacks, such as with the linux kernel's [IBT].
+
+```sh
+RUSTFLAGS="-Zno-jump-tables" cargo +nightly build -Z build-std
+```
+
+[IBT]: https://www.phoronix.com/news/Linux-IBT-By-Default-Tip
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index de911f7a028..a2903e52ae0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
     if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
-                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
+                let path_str = rustc_hir_pretty::qpath_to_string(path);
                 if path_str == "Err" {
                     let mut matching_wild = inner.iter().any(is_wild);
                     let mut ident_bind_name = kw::Underscore;
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index e53e146ec5d..01b850cdb11 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                         cx,
                         arguments.iter().collect(),
                         cx.typeck_results().expr_ty(fn_expr),
-                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
+                        &rustc_hir_pretty::qpath_to_string(path),
                         "function",
                     );
                 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
new file mode 100644
index 00000000000..35307586391
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
@@ -0,0 +1,22 @@
+#![feature(diagnostic_namespace)]
+
+#[diagnostic::on_unimplemented(
+    //~^WARN malformed `on_unimplemented` attribute
+    //~|WARN malformed `on_unimplemented` attribute
+    if(Self = ()),
+    message = "not used yet",
+    label = "not used yet",
+    note = "not used yet"
+)]
+#[diagnostic::on_unimplemented(message = "fallback!!")]
+#[diagnostic::on_unimplemented(label = "fallback label")]
+#[diagnostic::on_unimplemented(note = "fallback note")]
+#[diagnostic::on_unimplemented(message = "fallback2!!")]
+trait Foo {}
+
+fn takes_foo(_: impl Foo) {}
+
+fn main() {
+    takes_foo(());
+    //~^ERROR fallback!!
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
new file mode 100644
index 00000000000..6a83d8e39c6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
@@ -0,0 +1,52 @@
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+   |
+LL | / #[diagnostic::on_unimplemented(
+LL | |
+LL | |
+LL | |     if(Self = ()),
+...  |
+LL | |     note = "not used yet"
+LL | | )]
+   | |__^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+   |
+LL | / #[diagnostic::on_unimplemented(
+LL | |
+LL | |
+LL | |     if(Self = ()),
+...  |
+LL | |     note = "not used yet"
+LL | | )]
+   | |__^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: fallback!!
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
+   |
+LL |     takes_foo(());
+   |     --------- ^^ fallback label
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo` is not implemented for `()`
+   = note: fallback note
+help: this trait has no implementations, consider adding one
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
+note: required by a bound in `takes_foo`
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
+   |
+LL | fn takes_foo(_: impl Foo) {}
+   |                      ^^^ required by this bound in `takes_foo`
+
+error: aborting due to previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.