about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-20 19:37:17 +0000
committerbors <bors@rust-lang.org>2022-07-20 19:37:17 +0000
commitd68e7ebc38cb42b8b237392b28045edeec761503 (patch)
treee8109432f17346411b536b520111848a173e8cf1
parenta7468c60f8dbf5feb23ad840b174d7e57113a846 (diff)
parenta5a681100cb14af73926f309821903175b4fc2a2 (diff)
downloadrust-d68e7ebc38cb42b8b237392b28045edeec761503.tar.gz
rust-d68e7ebc38cb42b8b237392b28045edeec761503.zip
Auto merge of #99520 - matthiaskrgr:rollup-05uuv5s, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #99212 (introduce `implied_by` in `#[unstable]` attribute)
 - #99352 (Use `typeck_results` to avoid duplicate `ast_ty_to_ty` call)
 - #99355 (better error for bad depth parameter on macro metavar expr)
 - #99480 (Diagnostic width span is not added when '0$' is used as width in format strings)
 - #99488 (compiletest: Allow using revisions with debuginfo tests.)
 - #99489 (rustdoc UI fixes)
 - #99508 (Avoid `Symbol` to `String` conversions)
 - #99510 (adapt assembly/static-relocation-model test for LLVM change)
 - #99516 (Use new tracking issue for proc_macro::tracked_*.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_attr/src/builtin.rs49
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs6
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs15
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs13
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs14
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs24
-rw-r--r--compiler/rustc_middle/src/query/mod.rs8
-rw-r--r--compiler/rustc_parse_format/src/lib.rs3
-rw-r--r--compiler/rustc_parse_format/src/tests.rs17
-rw-r--r--compiler/rustc_passes/src/lib_features.rs18
-rw-r--r--compiler/rustc_passes/src/stability.rs123
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/macros.rs11
-rw-r--r--compiler/rustc_span/src/source_map.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs18
-rw-r--r--library/proc_macro/src/lib.rs8
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css5
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css8
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css8
-rw-r--r--src/librustdoc/html/static/css/themes/light.css8
-rw-r--r--src/test/assembly/static-relocation-model.rs7
-rw-r--r--src/test/debuginfo/basic-types-globals-lto.rs81
-rw-r--r--src/test/debuginfo/basic-types-globals.rs6
-rw-r--r--src/test/rustdoc-gui/search-input.goml23
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml2
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.rs3
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr15
-rw-r--r--src/test/ui/kindck/kindck-copy.stderr8
-rw-r--r--src/test/ui/macros/meta-variable-depth-outside-repeat.rs12
-rw-r--r--src/test/ui/macros/meta-variable-depth-outside-repeat.stderr8
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs9
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr6
-rw-r--r--src/test/ui/not-panic/not-panic-safe.stderr7
-rw-r--r--src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs8
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-missing.rs10
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr8
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs13
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr21
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs15
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr22
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs17
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr22
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr2
-rw-r--r--src/test/ui/traits/issue-32963.rs1
-rw-r--r--src/test/ui/traits/issue-32963.stderr17
-rw-r--r--src/test/ui/traits/suggest-where-clause.stderr4
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr7
-rw-r--r--src/tools/compiletest/src/header.rs36
-rw-r--r--src/tools/compiletest/src/runtest.rs27
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs15
60 files changed, 584 insertions, 254 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index dcfbecedfe8..64a6f91f022 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -135,9 +135,42 @@ impl ConstStability {
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub enum StabilityLevel {
-    // Reason for the current stability level and the relevant rust-lang issue
-    Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
-    Stable { since: Symbol, allowed_through_unstable_modules: bool },
+    /// `#[unstable]`
+    Unstable {
+        /// Reason for the current stability level.
+        reason: Option<Symbol>,
+        /// Relevant `rust-lang/rust` issue.
+        issue: Option<NonZeroU32>,
+        is_soft: bool,
+        /// If part of a feature is stabilized and a new feature is added for the remaining parts,
+        /// then the `implied_by` attribute is used to indicate which now-stable feature previously
+        /// contained a item.
+        ///
+        /// ```pseudo-Rust
+        /// #[unstable(feature = "foo", issue = "...")]
+        /// fn foo() {}
+        /// #[unstable(feature = "foo", issue = "...")]
+        /// fn foobar() {}
+        /// ```
+        ///
+        /// ...becomes...
+        ///
+        /// ```pseudo-Rust
+        /// #[stable(feature = "foo", since = "1.XX.X")]
+        /// fn foo() {}
+        /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
+        /// fn foobar() {}
+        /// ```
+        implied_by: Option<Symbol>,
+    },
+    /// `#[stable]`
+    Stable {
+        /// Rust release which stabilized this feature.
+        since: Symbol,
+        /// Is this item allowed to be referred to on stable, despite being contained in unstable
+        /// modules?
+        allowed_through_unstable_modules: bool,
+    },
 }
 
 impl StabilityLevel {
@@ -243,6 +276,7 @@ where
                     let mut issue = None;
                     let mut issue_num = None;
                     let mut is_soft = false;
+                    let mut implied_by = None;
                     for meta in metas {
                         let Some(mi) = meta.meta_item() else {
                             handle_errors(
@@ -308,6 +342,11 @@ where
                                 }
                                 is_soft = true;
                             }
+                            sym::implied_by => {
+                                if !get(mi, &mut implied_by) {
+                                    continue 'outer;
+                                }
+                            }
                             _ => {
                                 handle_errors(
                                     &sess.parse_sess,
@@ -332,7 +371,7 @@ where
                                 );
                                 continue;
                             }
-                            let level = Unstable { reason, issue: issue_num, is_soft };
+                            let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
                             if sym::unstable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
                             } else {
@@ -391,7 +430,7 @@ where
                                         meta.span(),
                                         AttrError::UnknownMetaItem(
                                             pprust::path_to_string(&mi.path),
-                                            &["since", "note"],
+                                            &["feature", "since"],
                                         ),
                                     );
                                     continue 'outer;
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 3b7e2102ffa..ce897abb766 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -485,7 +485,7 @@ impl<'a, 'b> Context<'a, 'b> {
             if let Some(span) = fmt.width_span {
                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.width {
-                    parse::CountIsParam(pos) if pos > self.num_args() => {
+                    parse::CountIsParam(pos) if pos >= self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -1004,9 +1004,7 @@ fn lint_named_arguments_used_positionally(
                 node_id: ast::CRATE_NODE_ID,
                 lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
-                    arg_span,
-                    span,
-                    symbol.to_string(),
+                    arg_span, span, symbol,
                 ),
             });
         }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 7d7f3e18335..ba888d77b15 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -390,18 +390,17 @@ impl Diagnostic {
         expected: DiagnosticStyledString,
         found: DiagnosticStyledString,
     ) -> &mut Self {
-        let mut msg: Vec<_> =
-            vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)];
+        let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)];
         msg.extend(expected.0.iter().map(|x| match *x {
-            StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
-            StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+            StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
+            StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
         }));
-        msg.push(("` to type '".to_string(), Style::NoStyle));
+        msg.push(("` to type '", Style::NoStyle));
         msg.extend(found.0.iter().map(|x| match *x {
-            StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
-            StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+            StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
+            StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
         }));
-        msg.push(("`".to_string(), Style::NoStyle));
+        msg.push(("`", Style::NoStyle));
 
         // For now, just attach these as notes
         self.highlighted_note(msg);
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index fdd8dc93fc1..3037855ae28 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -512,7 +512,18 @@ fn out_of_bounds_err<'a>(
     span: Span,
     ty: &str,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-    cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
+    let msg = if max == 0 {
+        format!(
+            "meta-variable expression `{ty}` with depth parameter \
+             must be called inside of a macro repetition"
+        )
+    } else {
+        format!(
+            "depth parameter on meta-variable expression `{ty}` \
+             must be less than {max}"
+        )
+    };
+    cx.struct_span_err(span, &msg)
 }
 
 fn transcribe_metavar_expr<'a>(
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4fd57ed8533..3872d866dee 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,7 +467,7 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally(Option<Span>, Span, Symbol),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index f0874f8f2da..aa5705d3fcd 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -951,6 +951,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
     }
 
+    /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute
+    /// has an `implied_by` meta item, then the mapping from the implied feature to the actual
+    /// feature is a stability implication).
+    fn get_stability_implications(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] {
+        tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self))
+    }
+
     /// Iterates over the language items in the given crate.
     fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
         tcx.arena.alloc_from_iter(
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 565eec18ea9..65cae29c58d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -291,6 +291,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
+    stability_implications => {
+        cdata.get_stability_implications(tcx).iter().copied().collect()
+    }
     is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8e973009777..50d983754e8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -538,6 +538,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let lib_features = self.encode_lib_features();
         let lib_feature_bytes = self.position() - i;
 
+        // Encode the stability implications.
+        i = self.position();
+        let stability_implications = self.encode_stability_implications();
+        let stability_implications_bytes = self.position() - i;
+
         // Encode the language items.
         i = self.position();
         let lang_items = self.encode_lang_items();
@@ -686,6 +691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             crate_deps,
             dylib_dependency_formats,
             lib_features,
+            stability_implications,
             lang_items,
             diagnostic_items,
             lang_items_missing,
@@ -710,6 +716,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let computed_total_bytes = preamble_bytes
             + dep_bytes
             + lib_feature_bytes
+            + stability_implications_bytes
             + lang_item_bytes
             + diagnostic_item_bytes
             + native_lib_bytes
@@ -761,6 +768,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             p("preamble", preamble_bytes);
             p("dep", dep_bytes);
             p("lib feature", lib_feature_bytes);
+            p("stability_implications", stability_implications_bytes);
             p("lang item", lang_item_bytes);
             p("diagnostic item", diagnostic_item_bytes);
             p("native lib", native_lib_bytes);
@@ -1777,6 +1785,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(lib_features.to_vec())
     }
 
+    fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> {
+        empty_proc_macro!(self);
+        let tcx = self.tcx;
+        let implications = tcx.stability_implications(LOCAL_CRATE);
+        self.lazy_array(implications.iter().map(|(k, v)| (*k, *v)))
+    }
+
     fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index af1c09f4ae8..0f291f92647 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -226,6 +226,7 @@ pub(crate) struct CrateRoot {
     crate_deps: LazyArray<CrateDep>,
     dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
     lib_features: LazyArray<(Symbol, Option<Symbol>)>,
+    stability_implications: LazyArray<(Symbol, Symbol)>,
     lang_items: LazyArray<(DefIndex, usize)>,
     lang_items_missing: LazyArray<lang_items::LangItem>,
     diagnostic_items: LazyArray<(Symbol, DefIndex)>,
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index fc35cafcc77..8dc68b1f5a8 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -3,14 +3,14 @@ pub mod dependency_format;
 pub mod exported_symbols;
 pub mod lang_items;
 pub mod lib_features {
-    use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-    use rustc_span::symbol::Symbol;
+    use rustc_data_structures::fx::FxHashMap;
+    use rustc_span::{symbol::Symbol, Span};
 
     #[derive(HashStable, Debug)]
     pub struct LibFeatures {
-        // A map from feature to stabilisation version.
-        pub stable: FxHashMap<Symbol, Symbol>,
-        pub unstable: FxHashSet<Symbol>,
+        /// A map from feature to stabilisation version.
+        pub stable: FxHashMap<Symbol, (Symbol, Span)>,
+        pub unstable: FxHashMap<Symbol, Span>,
     }
 
     impl LibFeatures {
@@ -18,8 +18,8 @@ pub mod lib_features {
             let mut all_features: Vec<_> = self
                 .stable
                 .iter()
-                .map(|(f, s)| (*f, Some(*s)))
-                .chain(self.unstable.iter().map(|f| (*f, None)))
+                .map(|(f, (s, _))| (*f, Some(*s)))
+                .chain(self.unstable.iter().map(|(f, _)| (*f, None)))
                 .collect();
             all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap());
             all_features
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 96e068a3601..0fbad3f0f0f 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -62,6 +62,19 @@ pub struct Index {
     pub stab_map: FxHashMap<LocalDefId, Stability>,
     pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
     pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
+    /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
+    /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
+    /// exists, then this map will have a `impliee -> implier` entry.
+    ///
+    /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
+    /// specify their implications (both `implies` and `implied_by`). If only one of the two
+    /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
+    /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
+    /// reported, only the `#[stable]` attribute information is available, so the map is necessary
+    /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
+    /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
+    /// unstable feature" error for a feature that was implied.
+    pub implications: FxHashMap<Symbol, Symbol>,
 }
 
 impl Index {
@@ -423,7 +436,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(Stability {
-                level: attr::Unstable { reason, issue, is_soft }, feature, ..
+                level: attr::Unstable { reason, issue, is_soft, implied_by },
+                feature,
+                ..
             }) => {
                 if span.allows_unstable(feature) {
                     debug!("stability: skipping span={:?} since it is internal", span);
@@ -433,6 +448,13 @@ impl<'tcx> TyCtxt<'tcx> {
                     return EvalResult::Allow;
                 }
 
+                // If this item was previously part of a now-stabilized feature which is still
+                // active (i.e. the user hasn't removed the attribute for the stabilized feature
+                // yet) then allow use of this item.
+                if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+                    return EvalResult::Allow;
+                }
+
                 // When we're compiling the compiler itself we may pull in
                 // crates from crates.io, but those crates may depend on other
                 // crates also pulled in from crates.io. We want to ideally be
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 0581ef41f66..466a0fc25f7 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1634,11 +1634,15 @@ rustc_queries! {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the lib features map" }
     }
-    query defined_lib_features(_: CrateNum)
-        -> &'tcx [(Symbol, Option<Symbol>)] {
+    query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] {
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
+    query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+        storage(ArenaCacheSelector<'tcx>)
+        desc { "calculating the implications between `#[unstable]` features defined in a crate" }
+        separate_provide_extern
+    }
     /// Whether the function is an intrinsic
     query is_intrinsic(def_id: DefId) -> bool {
         desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index f6fa19030ac..6e7553f5e49 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -572,9 +572,10 @@ impl<'a> Parser<'a> {
             // '0' flag and then an ill-formatted format string with just a '$'
             // and no count, but this is better if we instead interpret this as
             // no '0' flag and '0$' as the width instead.
-            if self.consume('$') {
+            if let Some(end) = self.consume_pos('$') {
                 spec.width = CountIsParam(0);
                 havewidth = true;
+                spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
             } else {
                 spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
             }
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index c9667922ee7..9c305b4996a 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -179,6 +179,23 @@ fn format_counts() {
         })],
     );
     same(
+        "{1:0$.10x}",
+        &[NextArgument(Argument {
+            position: ArgumentIs(1),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIs(10),
+                width: CountIsParam(0),
+                precision_span: None,
+                width_span: Some(InnerSpan::new(4, 6)),
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
         "{:.*x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(1),
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 26bfa4737a7..e05994f13e4 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -1,8 +1,8 @@
-// Detecting lib features (i.e., features that are not lang features).
-//
-// These are declared using stability attributes (e.g., `#[stable (..)]`
-// and `#[unstable (..)]`), but are not declared in one single location
-// (unlike lang features), which means we need to collect them instead.
+//! Detecting lib features (i.e., features that are not lang features).
+//!
+//! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`),
+//! but are not declared in one single location (unlike lang features), which means we need to
+//! collect them instead.
 
 use rustc_ast::{Attribute, MetaItemKind};
 use rustc_errors::struct_span_err;
@@ -71,11 +71,11 @@ impl<'tcx> LibFeatureCollector<'tcx> {
 
     fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) {
         let already_in_stable = self.lib_features.stable.contains_key(&feature);
-        let already_in_unstable = self.lib_features.unstable.contains(&feature);
+        let already_in_unstable = self.lib_features.unstable.contains_key(&feature);
 
         match (since, already_in_stable, already_in_unstable) {
             (Some(since), _, false) => {
-                if let Some(prev_since) = self.lib_features.stable.get(&feature) {
+                if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
                     if *prev_since != since {
                         self.span_feature_error(
                             span,
@@ -89,10 +89,10 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                     }
                 }
 
-                self.lib_features.stable.insert(feature, since);
+                self.lib_features.stable.insert(feature, (since, span));
             }
             (None, false, _) => {
-                self.lib_features.unstable.insert(feature);
+                self.lib_features.unstable.insert(feature, span);
             }
             (Some(_), _, true) | (None, true, _) => {
                 self.span_feature_error(
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4e091c5b70d..81b04c414ed 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -2,9 +2,9 @@
 //! propagating default levels lexically from parent to children ast nodes.
 
 use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_errors::struct_span_err;
+use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -29,13 +29,13 @@ use std::num::NonZeroU32;
 
 #[derive(PartialEq)]
 enum AnnotationKind {
-    // Annotation is required if not inherited from unstable parents
+    /// Annotation is required if not inherited from unstable parents.
     Required,
-    // Annotation is useless, reject it
+    /// Annotation is useless, reject it.
     Prohibited,
-    // Deprecation annotation is useless, reject it. (Stability attribute is still required.)
+    /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
     DeprecationProhibited,
-    // Annotation itself is useless, but it can be propagated to children
+    /// Annotation itself is useless, but it can be propagated to children.
     Container,
 }
 
@@ -83,7 +83,7 @@ impl InheritStability {
     }
 }
 
-// A private tree-walker for producing an Index.
+/// A private tree-walker for producing an `Index`.
 struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     index: &'a mut Index,
@@ -94,9 +94,9 @@ struct Annotator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Annotator<'a, 'tcx> {
-    // Determine the stability for a node based on its attributes and inherited
-    // stability. The stability is recorded in the index and used as the parent.
-    // If the node is a function, `fn_sig` is its signature
+    /// Determine the stability for a node based on its attributes and inherited stability. The
+    /// stability is recorded in the index and used as the parent. If the node is a function,
+    /// `fn_sig` is its signature.
     fn annotate<F>(
         &mut self,
         def_id: LocalDefId,
@@ -265,6 +265,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 }
             }
 
+            if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
+                self.index.implications.insert(implied_by, feature);
+            }
+
             self.index.stab_map.insert(def_id, stab);
             stab
         });
@@ -610,6 +614,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
         stab_map: Default::default(),
         const_stab_map: Default::default(),
         depr_map: Default::default(),
+        implications: Default::default(),
     };
 
     {
@@ -637,6 +642,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
                     reason: Some(Symbol::intern(reason)),
                     issue: NonZeroU32::new(27812),
                     is_soft: false,
+                    implied_by: None,
                 },
                 feature: sym::rustc_private,
             };
@@ -667,6 +673,7 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         check_mod_unstable_api_usage,
         stability_index,
+        stability_implications: |tcx, _| tcx.stability().implications.clone(),
         lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
         lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
         lookup_deprecation_entry: |tcx, id| {
@@ -945,32 +952,51 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     remaining_lib_features.remove(&sym::libc);
     remaining_lib_features.remove(&sym::test);
 
-    let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| {
-        for &(feature, since) in defined_features {
-            if let Some(since) = since {
-                if let Some(span) = remaining_lib_features.get(&feature) {
-                    // Warn if the user has enabled an already-stable lib feature.
-                    unnecessary_stable_feature_lint(tcx, *span, feature, since);
-                }
-            }
-            remaining_lib_features.remove(&feature);
-            if remaining_lib_features.is_empty() {
-                break;
-            }
-        }
-    };
-
     // We always collect the lib features declared in the current crate, even if there are
     // no unknown features, because the collection also does feature attribute validation.
-    let local_defined_features = tcx.lib_features(()).to_vec();
-    if !remaining_lib_features.is_empty() {
-        check_features(&mut remaining_lib_features, &local_defined_features);
+    let local_defined_features = tcx.lib_features(());
+    let mut all_lib_features: FxHashMap<_, _> =
+        local_defined_features.to_vec().iter().map(|el| *el).collect();
+    let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
+    for &cnum in tcx.crates(()) {
+        implications.extend(tcx.stability_implications(cnum));
+        all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el));
+    }
 
-        for &cnum in tcx.crates(()) {
+    // Check that every feature referenced by an `implied_by` exists (for features defined in the
+    // local crate).
+    for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) {
+        // Only `implied_by` needs to be checked, `feature` is guaranteed to exist.
+        if !all_lib_features.contains_key(implied_by) {
+            let span = local_defined_features
+                .stable
+                .get(feature)
+                .map(|(_, span)| span)
+                .or_else(|| local_defined_features.unstable.get(feature))
+                .expect("feature that implied another does not exist");
+            tcx.sess
+                .struct_span_err(
+                    *span,
+                    format!("feature `{implied_by}` implying `{feature}` does not exist"),
+                )
+                .emit();
+        }
+    }
+
+    if !remaining_lib_features.is_empty() {
+        for (feature, since) in all_lib_features.iter() {
+            if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
+                // Warn if the user has enabled an already-stable lib feature.
+                if let Some(implies) = implications.get(&feature) {
+                    unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
+                } else {
+                    unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
+                }
+            }
+            remaining_lib_features.remove(&feature);
             if remaining_lib_features.is_empty() {
                 break;
             }
-            check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum));
         }
     }
 
@@ -982,12 +1008,41 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     // don't lint about unused features. We should re-enable this one day!
 }
 
+fn unnecessary_partially_stable_feature_lint(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    feature: Symbol,
+    implies: Symbol,
+    since: Symbol,
+) {
+    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
+        lint.build(&format!(
+            "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
+             by the feature `{implies}`"
+        ))
+        .span_suggestion(
+            span,
+            &format!(
+                "if you are using features which are still unstable, change to using `{implies}`"
+            ),
+            implies,
+            Applicability::MaybeIncorrect,
+        )
+        .span_suggestion(
+            tcx.sess.source_map().span_extend_to_line(span),
+            "if you are using features which are now stable, remove this line",
+            "",
+            Applicability::MaybeIncorrect,
+        )
+        .emit();
+    });
+}
+
 fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) {
     tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
         lint.build(&format!(
-            "the feature `{}` has been stable since {} and no longer requires \
-                      an attribute to enable",
-            feature, since
+            "the feature `{feature}` has been stable since {since} and no longer requires an \
+             attribute to enable",
         ))
         .emit();
     });
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7a1695fc862..df13136dcce 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2603,9 +2603,9 @@ fn show_candidates(
                 .skip(1)
                 .all(|(_, descr, _, _)| descr == descr_first)
             {
-                descr_first.to_string()
+                descr_first
             } else {
-                "item".to_string()
+                "item"
             };
             let plural_descr =
                 if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 54dd15270a1..2b5eb12a8a8 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -796,9 +796,16 @@ impl<'a> Resolver<'a> {
     ) {
         let span = path.span;
         if let Some(stability) = &ext.stability {
-            if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level {
+            if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
+            {
                 let feature = stability.feature;
-                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
+
+                let is_allowed = |feature| {
+                    self.active_features.contains(&feature) || span.allows_unstable(feature)
+                };
+                let allowed_by_implication =
+                    implied_by.map(|feature| is_allowed(feature)).unwrap_or(false);
+                if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
                     let soft_handler =
                         |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index afbb88e9233..b4a4424e876 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -718,6 +718,11 @@ impl SourceMap {
         sp
     }
 
+    /// Extends the given `Span` to contain the entire line it is on.
+    pub fn span_extend_to_line(&self, sp: Span) -> Span {
+        self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
+    }
+
     /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
     /// `c`.
     pub fn span_until_char(&self, sp: Span, c: char) -> Span {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ec1d2c39b80..2ac1ecfe87e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -800,6 +800,7 @@ symbols! {
         impl_lint_pass,
         impl_macros,
         impl_trait_in_bindings,
+        implied_by,
         import,
         import_shadowing,
         imported_main,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index e3db70845dd..8aa8ac90b4c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1757,19 +1757,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .flat_map(|a| a.args.iter())
                         {
                             if let hir::GenericArg::Type(hir_ty) = &arg {
-                                if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
-                                    &hir_ty.kind
-                                {
-                                    // Avoid ICE with associated types. As this is best
-                                    // effort only, it's ok to ignore the case. It
-                                    // would trigger in `is_send::<T::AssocType>();`
-                                    // from `typeck-default-trait-impl-assoc-type.rs`.
-                                } else {
-                                    let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
-                                    let ty = self.resolve_vars_if_possible(ty);
-                                    if ty == predicate.self_ty() {
-                                        error.obligation.cause.span = hir_ty.span;
-                                    }
+                                let ty = self.resolve_vars_if_possible(
+                                    self.typeck_results.borrow().node_type(hir_ty.hir_id),
+                                );
+                                if ty == predicate.self_ty() {
+                                    error.obligation.cause.span = hir_ty.span;
                                 }
                             }
                         }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 5cf16bdd08c..08b45ac11a1 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1484,7 +1484,7 @@ impl fmt::Debug for Literal {
 }
 
 /// Tracked access to environment variables.
-#[unstable(feature = "proc_macro_tracked_env", issue = "74690")]
+#[unstable(feature = "proc_macro_tracked_env", issue = "99515")]
 pub mod tracked_env {
     use std::env::{self, VarError};
     use std::ffi::OsStr;
@@ -1494,7 +1494,7 @@ pub mod tracked_env {
     /// compilation, and will be able to rerun the build when the value of that variable changes.
     /// Besides the dependency tracking this function should be equivalent to `env::var` from the
     /// standard library, except that the argument must be UTF-8.
-    #[unstable(feature = "proc_macro_tracked_env", issue = "74690")]
+    #[unstable(feature = "proc_macro_tracked_env", issue = "99515")]
     pub fn var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> {
         let key: &str = key.as_ref();
         let value = env::var(key);
@@ -1504,13 +1504,13 @@ pub mod tracked_env {
 }
 
 /// Tracked access to additional files.
-#[unstable(feature = "track_path", issue = "73921")]
+#[unstable(feature = "track_path", issue = "99515")]
 pub mod tracked_path {
 
     /// Track a file explicitly.
     ///
     /// Commonly used for tracking asset preprocessing.
-    #[unstable(feature = "track_path", issue = "73921")]
+    #[unstable(feature = "track_path", issue = "99515")]
     pub fn path<P: AsRef<str>>(path: P) {
         let path: &str = path.as_ref();
         crate::bridge::client::FreeFunctions::track_path(path);
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index c6933a8254b..69409b77251 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -949,7 +949,7 @@ table,
 #crate-search {
 	min-width: 115px;
 	margin-top: 5px;
-	padding-left: 0.3125em;
+	padding-left: 0.15em;
 	padding-right: 23px;
 	border: 1px solid;
 	border-radius: 4px;
@@ -958,8 +958,6 @@ table,
 	-moz-appearance: none;
 	-webkit-appearance: none;
 	/* Removes default arrow from firefox */
-	text-indent: 0.01px;
-	text-overflow: "";
 	background-repeat: no-repeat;
 	background-color: transparent;
 	background-size: 20px;
@@ -986,7 +984,6 @@ table,
 	border-radius: 2px;
 	padding: 8px;
 	font-size: 1rem;
-	transition: border-color 300ms ease;
 	width: 100%;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 142ce456c52..7ff8063904a 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -184,7 +184,13 @@ details.rustdoc-toggle > summary::before {
 
 #crate-search, .search-input {
 	background-color: #141920;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #424c57;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #424c57 !important;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index aeaca7515f9..8e753f57682 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -159,7 +159,13 @@ details.rustdoc-toggle > summary::before {
 #crate-search, .search-input {
 	color: #111;
 	background-color: #f0f0f0;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #f0f0f0;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #f0f0f0 !important;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 54d1a7b65d6..40d965c39c3 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -146,7 +146,13 @@ details.rustdoc-toggle > summary::before {
 
 #crate-search, .search-input {
 	background-color: white;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #e0e0e0;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #e0e0e0 !important;
 }
 
diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs
index 6c41e0b78f1..faa2e395209 100644
--- a/src/test/assembly/static-relocation-model.rs
+++ b/src/test/assembly/static-relocation-model.rs
@@ -36,7 +36,8 @@ extern "C" {
 }
 
 // CHECK-LABEL: banana:
-// x64: movb   chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
+// On the next line LLVM 14 produces a `movb`, whereas LLVM 15+ produces a `movzbl`.
+// x64: {{movb|movzbl}}   chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG:[a-z0-9]+]], chaenomeles
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles]
 #[no_mangle]
@@ -47,7 +48,7 @@ pub fn banana() -> u8 {
 }
 
 // CHECK-LABEL: peach:
-// x64: movb    banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
+// x64: {{movb|movzbl}}    banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG2:[a-z0-9]+]], banana
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana]
 #[no_mangle]
@@ -59,7 +60,7 @@ pub fn peach() -> u8 {
 
 // CHECK-LABEL: mango:
 // x64:      movq    EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]]
-// x64-NEXT: movb    (%[[REG]]), %{{[a-z0-9]+}}
+// x64-NEXT: {{movb|movzbl}}   (%[[REG]]), %{{[a-z0-9]+}}
 // A64:      adrp    [[REG2:[a-z0-9]+]], EXOCHORDA
 // A64-NEXT: ldr     {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA]
 #[no_mangle]
diff --git a/src/test/debuginfo/basic-types-globals-lto.rs b/src/test/debuginfo/basic-types-globals-lto.rs
deleted file mode 100644
index 1adf278ad32..00000000000
--- a/src/test/debuginfo/basic-types-globals-lto.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Caveat - gdb doesn't know about UTF-32 character encoding and will print a
-// rust char as only its numerical value.
-
-// min-lldb-version: 310
-// min-gdb-version: 8.0
-
-// no-prefer-dynamic
-// compile-flags:-g -C lto
-// gdb-command:run
-// gdbg-command:print 'basic_types_globals::B'
-// gdbr-command:print B
-// gdb-check:$1 = false
-// gdbg-command:print 'basic_types_globals::I'
-// gdbr-command:print I
-// gdb-check:$2 = -1
-// gdbg-command:print 'basic_types_globals::C'
-// gdbr-command:print/d C
-// gdbg-check:$3 = 97
-// gdbr-check:$3 = 97
-// gdbg-command:print/d 'basic_types_globals::I8'
-// gdbr-command:print I8
-// gdb-check:$4 = 68
-// gdbg-command:print 'basic_types_globals::I16'
-// gdbr-command:print I16
-// gdb-check:$5 = -16
-// gdbg-command:print 'basic_types_globals::I32'
-// gdbr-command:print I32
-// gdb-check:$6 = -32
-// gdbg-command:print 'basic_types_globals::I64'
-// gdbr-command:print I64
-// gdb-check:$7 = -64
-// gdbg-command:print 'basic_types_globals::U'
-// gdbr-command:print U
-// gdb-check:$8 = 1
-// gdbg-command:print/d 'basic_types_globals::U8'
-// gdbr-command:print U8
-// gdb-check:$9 = 100
-// gdbg-command:print 'basic_types_globals::U16'
-// gdbr-command:print U16
-// gdb-check:$10 = 16
-// gdbg-command:print 'basic_types_globals::U32'
-// gdbr-command:print U32
-// gdb-check:$11 = 32
-// gdbg-command:print 'basic_types_globals::U64'
-// gdbr-command:print U64
-// gdb-check:$12 = 64
-// gdbg-command:print 'basic_types_globals::F32'
-// gdbr-command:print F32
-// gdb-check:$13 = 2.5
-// gdbg-command:print 'basic_types_globals::F64'
-// gdbr-command:print F64
-// gdb-check:$14 = 3.5
-// gdb-command:continue
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// N.B. These are `mut` only so they don't constant fold away.
-static mut B: bool = false;
-static mut I: isize = -1;
-static mut C: char = 'a';
-static mut I8: i8 = 68;
-static mut I16: i16 = -16;
-static mut I32: i32 = -32;
-static mut I64: i64 = -64;
-static mut U: usize = 1;
-static mut U8: u8 = 100;
-static mut U16: u16 = 16;
-static mut U32: u32 = 32;
-static mut U64: u64 = 64;
-static mut F32: f32 = 2.5;
-static mut F64: f64 = 3.5;
-
-fn main() {
-    _zzz(); // #break
-
-    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
-}
-
-fn _zzz() {()}
diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs
index 3602db39a4e..8a3df8ba2d1 100644
--- a/src/test/debuginfo/basic-types-globals.rs
+++ b/src/test/debuginfo/basic-types-globals.rs
@@ -4,7 +4,13 @@
 // min-lldb-version: 310
 // min-gdb-version: 8.0
 
+// revisions: lto no-lto
+
 // compile-flags:-g
+
+// [lto] compile-flags:-C lto
+// [lto] no-prefer-dynamic
+
 // gdb-command:run
 // gdbg-command:print 'basic_types_globals::B'
 // gdbr-command:print B
diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml
new file mode 100644
index 00000000000..44123b702df
--- /dev/null
+++ b/src/test/rustdoc-gui/search-input.goml
@@ -0,0 +1,23 @@
+// Ensures that the search input border color changes on focus.
+goto: file://|DOC_PATH|/test_docs/index.html
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+focus: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"})
+
+local-storage: {"rustdoc-theme": "light"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"})
+
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index 6295d7fae89..8464ba7c23c 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -18,7 +18,7 @@ assert-css: (".search-results div.desc", {"width": "570px"})
 size: (900, 900)
 
 // First we check the current width and position.
-assert-css: ("#crate-search", {"width": "222px"})
+assert-css: ("#crate-search", {"width": "218px"})
 compare-elements-position-near: (
     "#crate-search",
     "#search-settings .search-results-title",
diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs
index b3e54ed32aa..84f4cc7f4cc 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.rs
+++ b/src/test/ui/fmt/ifmt-bad-arg.rs
@@ -86,6 +86,9 @@ tenth number: {}",
     println!("{:foo}", 1); //~ ERROR unknown format trait `foo`
     println!("{5} {:4$} {6:7$}", 1);
     //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument)
+    let foo = 1;
+    println!("{foo:0$}");
+    //~^ ERROR invalid reference to positional argument 0 (no arguments were given)
 
     // We used to ICE here because we tried to unconditionally access the first argument, which
     // doesn't exist.
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index d181fe14107..5439ee17398 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -251,8 +251,19 @@ LL |     println!("{5} {:4$} {6:7$}", 1);
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: invalid reference to positional argument 0 (no arguments were given)
+  --> $DIR/ifmt-bad-arg.rs:90:15
+   |
+LL |     println!("{foo:0$}");
+   |               ^^^^^--^
+   |                    |
+   |                    this width flag expects an `usize` argument at position 0, but no arguments were given
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error: 2 positional arguments in format string, but no arguments were given
-  --> $DIR/ifmt-bad-arg.rs:92:15
+  --> $DIR/ifmt-bad-arg.rs:95:15
    |
 LL |     println!("{:.*}");
    |               ^^--^
@@ -328,7 +339,7 @@ LL |     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
    |            ^^^^^^^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 36 previous errors
+error: aborting due to 37 previous errors
 
 Some errors have detailed explanations: E0308, E0425.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr
index 1c61c85368b..025a5008d0f 100644
--- a/src/test/ui/kindck/kindck-copy.stderr
+++ b/src/test/ui/kindck/kindck-copy.stderr
@@ -91,10 +91,10 @@ LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:42:5
+  --> $DIR/kindck-copy.rs:42:19
    |
 LL |     assert_copy::<Box<dyn Dummy>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
+   |                   ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
    |
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
@@ -103,10 +103,10 @@ LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:43:5
+  --> $DIR/kindck-copy.rs:43:19
    |
 LL |     assert_copy::<Box<dyn Dummy + Send>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
+   |                   ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
    |
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.rs b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs
new file mode 100644
index 00000000000..b7fb947854f
--- /dev/null
+++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs
@@ -0,0 +1,12 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! metavar {
+    ( $i:expr ) => {
+        ${length(0)}
+        //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+    };
+}
+
+const _: i32 = metavar!(0);
+
+fn main() {}
diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr
new file mode 100644
index 00000000000..fad150cadfc
--- /dev/null
+++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr
@@ -0,0 +1,8 @@
+error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+  --> $DIR/meta-variable-depth-outside-repeat.rs:5:10
+   |
+LL |         ${length(0)}
+   |          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
index d81c8628bab..6a0d68bd6b1 100644
--- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -5,7 +5,7 @@ macro_rules! a {
         (
             ${count(foo, 0)},
             ${count(foo, 10)},
-            //~^ ERROR count depth must be less than 4
+            //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
         )
     };
 }
@@ -17,7 +17,7 @@ macro_rules! b {
                 ${ignore(foo)}
                 ${index(0)},
                 ${index(10)},
-                //~^ ERROR index depth must be less than 3
+                //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
             )* )* )*
         )
     };
@@ -30,15 +30,14 @@ macro_rules! c {
                 ${ignore(foo)}
                 ${length(0)}
                 ${length(10)}
-                //~^ ERROR length depth must be less than 2
+                //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
             )* )*
         )
     };
 }
 
-
 fn main() {
     a!( { [ (a) ] [ (b c) ] } );
     b!( { [ a b ] } );
-    c!( { a } );
+    c!({ a });
 }
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
index 7474c03c0f9..236122b6465 100644
--- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -1,16 +1,16 @@
-error: count depth must be less than 4
+error: depth parameter on meta-variable expression `count` must be less than 4
   --> $DIR/out-of-bounds-arguments.rs:7:14
    |
 LL |             ${count(foo, 10)},
    |              ^^^^^^^^^^^^^^^^
 
-error: index depth must be less than 3
+error: depth parameter on meta-variable expression `index` must be less than 3
   --> $DIR/out-of-bounds-arguments.rs:19:18
    |
 LL |                 ${index(10)},
    |                  ^^^^^^^^^^^
 
-error: length depth must be less than 2
+error: depth parameter on meta-variable expression `length` must be less than 2
   --> $DIR/out-of-bounds-arguments.rs:32:18
    |
 LL |                 ${length(10)}
diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr
index 3e54df12376..2cd51a43998 100644
--- a/src/test/ui/not-panic/not-panic-safe.stderr
+++ b/src/test/ui/not-panic/not-panic-safe.stderr
@@ -1,8 +1,11 @@
 error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
-  --> $DIR/not-panic-safe.rs:8:5
+  --> $DIR/not-panic-safe.rs:8:14
    |
 LL |     assert::<&mut i32>();
-   |     ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
+   |              -^^^^^^^
+   |              |
+   |              `&mut i32` may not be safely transferred across an unwind boundary
+   |              help: consider removing the leading `&`-reference
    |
    = help: the trait `UnwindSafe` is not implemented for `&mut i32`
    = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
diff --git a/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
new file mode 100644
index 00000000000..468be1bc144
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
@@ -0,0 +1,8 @@
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.62.0")]
+pub fn foo() {}
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "foo")]
+pub fn foobar() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs
new file mode 100644
index 00000000000..61387853672
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+// Tests that `implied_by = "bar"` results in an error being emitted if `bar` does not exist.
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+//~^ ERROR feature `bar` implying `foobar` does not exist
+pub fn foobar() {}
+
+fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr
new file mode 100644
index 00000000000..ff1856f1763
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr
@@ -0,0 +1,8 @@
+error: feature `bar` implying `foobar` does not exist
+  --> $DIR/stability-attribute-implies-missing.rs:6:1
+   |
+LL | #[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
new file mode 100644
index 00000000000..947f9f73eff
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
@@ -0,0 +1,13 @@
+// aux-build:stability-attribute-implies.rs
+
+// Tests that despite the `foobar` feature being implied by now-stable feature `foo`, if `foobar`
+// isn't allowed in this crate then an error will be emitted.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+//~^ ERROR use of unstable library feature 'foobar'
+
+fn main() {
+    foo(); // no error - stable
+    foobar(); //~ ERROR use of unstable library feature 'foobar'
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
new file mode 100644
index 00000000000..c2331f6766c
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
@@ -0,0 +1,21 @@
+error[E0658]: use of unstable library feature 'foobar'
+  --> $DIR/stability-attribute-implies-no-feature.rs:7:40
+   |
+LL | use stability_attribute_implies::{foo, foobar};
+   |                                        ^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'foobar'
+  --> $DIR/stability-attribute-implies-no-feature.rs:12:5
+   |
+LL |     foobar();
+   |     ^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
new file mode 100644
index 00000000000..1a2d8e271de
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
@@ -0,0 +1,15 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization, and that given the implied unstable feature is unused (there
+// is no `foobar` call), that the compiler suggests removing the flag.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::foo;
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
new file mode 100644
index 00000000000..c9b3f07cc70
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
@@ -0,0 +1,22 @@
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+  --> $DIR/stability-attribute-implies-using-stable.rs:3:12
+   |
+LL | #![feature(foo)]
+   |            ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/stability-attribute-implies-using-stable.rs:2:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+   |
+LL | #![feature(foobar)]
+   |            ~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
new file mode 100644
index 00000000000..3c73c5abf3b
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
@@ -0,0 +1,17 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization and that given the implied unstable feature is used (there is a
+// `foobar` call), that the compiler suggests changing to that feature and doesn't error about its
+// use.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+
+fn main() {
+    foo();
+    foobar(); // no error!
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
new file mode 100644
index 00000000000..9a5c7ef5a47
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
@@ -0,0 +1,22 @@
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+  --> $DIR/stability-attribute-implies-using-unstable.rs:3:12
+   |
+LL | #![feature(foo)]
+   |            ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/stability-attribute-implies-using-unstable.rs:2:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+   |
+LL | #![feature(foobar)]
+   |            ~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
index bd7b88da158..8dbcc6c97ef 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
@@ -8,7 +8,7 @@ error[E0541]: unknown meta item 'sinse'
   --> $DIR/stability-attribute-sanity-2.rs:10:25
    |
 LL | #[stable(feature = "a", sinse = "1.0.0")]
-   |                         ^^^^^^^^^^^^^^^ expected one of `since`, `note`
+   |                         ^^^^^^^^^^^^^^^ expected one of `feature`, `since`
 
 error[E0545]: `issue` must be a non-zero numeric string or "none"
   --> $DIR/stability-attribute-sanity-2.rs:13:27
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index fcb1eefddbc..079230b2a31 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -14,7 +14,7 @@ error[E0541]: unknown meta item 'reason'
   --> $DIR/stability-attribute-sanity.rs:8:42
    |
 LL |     #[stable(feature = "a", since = "b", reason)]
-   |                                          ^^^^^^ expected one of `since`, `note`
+   |                                          ^^^^^^ expected one of `feature`, `since`
 
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:11:29
diff --git a/src/test/ui/traits/issue-32963.rs b/src/test/ui/traits/issue-32963.rs
index 58055cd5456..56a68f3a231 100644
--- a/src/test/ui/traits/issue-32963.rs
+++ b/src/test/ui/traits/issue-32963.rs
@@ -7,6 +7,5 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 fn main() {
     size_of_copy::<dyn Misc + Copy>();
     //~^ ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR only auto traits can be used as additional traits in a trait object
     //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
 }
diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr
index 5e7762b3220..bad45e54d64 100644
--- a/src/test/ui/traits/issue-32963.stderr
+++ b/src/test/ui/traits/issue-32963.stderr
@@ -9,22 +9,11 @@ LL |     size_of_copy::<dyn Misc + Copy>();
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
 error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
-  --> $DIR/issue-32963.rs:8:5
+  --> $DIR/issue-32963.rs:8:20
    |
 LL |     size_of_copy::<dyn Misc + Copy>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
+   |                    ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
    |
 note: required by a bound in `size_of_copy`
   --> $DIR/issue-32963.rs:5:20
@@ -32,7 +21,7 @@ note: required by a bound in `size_of_copy`
 LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
    |                    ^^^^ required by this bound in `size_of_copy`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0225, E0277.
 For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr
index 21b339d12a8..d4d9b496747 100644
--- a/src/test/ui/traits/suggest-where-clause.stderr
+++ b/src/test/ui/traits/suggest-where-clause.stderr
@@ -85,10 +85,10 @@ LL | pub const fn size_of<T>() -> usize {
    |                      ^ required by this bound in `std::mem::size_of`
 
 error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
-  --> $DIR/suggest-where-clause.rs:31:5
+  --> $DIR/suggest-where-clause.rs:31:20
    |
 LL |     mem::size_of::<[&U]>();
-   |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                    ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[&U]`
 note: required by a bound in `std::mem::size_of`
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
index 7aefa064611..468a14762c0 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
-  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
+  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:15
    |
 LL |     is_send::<T::AssocType>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
+   |               ^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `<T as Trait>::AssocType`
 note: required by a bound in `is_send`
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
index 09d3eec6b21..a3b32d2c1c8 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq<dyn Foo<(isize,), Output = ()>>` is not satisfied
-  --> $DIR/unboxed-closure-sugar-default.rs:21:5
+  --> $DIR/unboxed-closure-sugar-default.rs:21:10
    |
 LL |     eq::<dyn Foo<(isize,), isize, Output=()>, dyn Foo(isize)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
    |
 note: required by a bound in `eq`
   --> $DIR/unboxed-closure-sugar-default.rs:14:40
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
index 0fc3e23ec73..acf0227a79b 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
@@ -42,7 +42,7 @@ fn test<'a,'b>() {
     // Errors expected:
     eq::< dyn Foo<(),Output=()>,
           dyn Foo(char)                                               >();
-    //~^^ ERROR E0277
+    //~^ ERROR E0277
 }
 
 fn main() { }
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
index a1cbf842a68..bccbf307ae1 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
@@ -1,9 +1,8 @@
 error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq<dyn Foo<(), Output = ()>>` is not satisfied
-  --> $DIR/unboxed-closure-sugar-equiv.rs:43:5
+  --> $DIR/unboxed-closure-sugar-equiv.rs:44:11
    |
-LL | /     eq::< dyn Foo<(),Output=()>,
-LL | |           dyn Foo(char)                                               >();
-   | |_______________________________________________________________________^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
+LL |           dyn Foo(char)                                               >();
+   |           ^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
    |
 note: required by a bound in `eq`
   --> $DIR/unboxed-closure-sugar-equiv.rs:16:28
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 17f2b77dab0..02f4d29a2f0 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -535,6 +535,29 @@ impl TestProps {
     }
 }
 
+pub fn line_directive<'line>(
+    comment: &str,
+    ln: &'line str,
+) -> Option<(Option<&'line str>, &'line str)> {
+    if ln.starts_with(comment) {
+        let ln = ln[comment.len()..].trim_start();
+        if ln.starts_with('[') {
+            // A comment like `//[foo]` is specific to revision `foo`
+            if let Some(close_brace) = ln.find(']') {
+                let lncfg = &ln[1..close_brace];
+
+                Some((Some(lncfg), ln[(close_brace + 1)..].trim_start()))
+            } else {
+                panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln)
+            }
+        } else {
+            Some((None, ln))
+        }
+    } else {
+        None
+    }
+}
+
 fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str)) {
     if testfile.is_dir() {
         return;
@@ -557,17 +580,8 @@ fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>
         let ln = ln.trim();
         if ln.starts_with("fn") || ln.starts_with("mod") {
             return;
-        } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') {
-            // A comment like `//[foo]` is specific to revision `foo`
-            if let Some(close_brace) = ln.find(']') {
-                let open_brace = ln.find('[').unwrap();
-                let lncfg = &ln[open_brace + 1..close_brace];
-                it(Some(lncfg), ln[(close_brace + 1)..].trim_start());
-            } else {
-                panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln)
-            }
-        } else if ln.starts_with(comment) {
-            it(None, ln[comment.len()..].trim_start());
+        } else if let Some((lncfg, ln)) = line_directive(comment, ln) {
+            it(lncfg, ln);
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5517b5a12c3..26730fcec4c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -648,8 +648,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_cdb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         let config = Config {
             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
@@ -695,7 +693,12 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
@@ -756,8 +759,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_gdb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         let config = Config {
             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
@@ -783,7 +784,12 @@ impl<'test> TestCx<'test> {
         };
 
         let DebuggerCommands { commands, check_lines, breakpoint_lines } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
@@ -1005,8 +1011,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_lldb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         if self.config.lldb_python_dir.is_none() {
             self.fatal("Can't run LLDB test because LLDB's python path is not set.");
         }
@@ -1059,7 +1063,12 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index cbd5e4c431f..379ff0bab40 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -1,4 +1,5 @@
 use crate::common::Config;
+use crate::header::line_directive;
 use crate::runtest::ProcRes;
 
 use std::fs::File;
@@ -16,6 +17,7 @@ impl DebuggerCommands {
         file: &Path,
         config: &Config,
         debugger_prefixes: &[&str],
+        rev: Option<&str>,
     ) -> Result<Self, String> {
         let directives = debugger_prefixes
             .iter()
@@ -25,13 +27,19 @@ impl DebuggerCommands {
         let mut breakpoint_lines = vec![];
         let mut commands = vec![];
         let mut check_lines = vec![];
-        let mut counter = 1;
+        let mut counter = 0;
         let reader = BufReader::new(File::open(file).unwrap());
         for line in reader.lines() {
+            counter += 1;
             match line {
                 Ok(line) => {
-                    let line =
-                        if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
+                    let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
+
+                    // Skip any revision specific directive that doesn't match the current
+                    // revision being tested
+                    if lnrev.is_some() && lnrev != rev {
+                        continue;
+                    }
 
                     if line.contains("#break") {
                         breakpoint_lines.push(counter);
@@ -49,7 +57,6 @@ impl DebuggerCommands {
                 }
                 Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)),
             }
-            counter += 1;
         }
 
         Ok(Self { commands, check_lines, breakpoint_lines })