about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-22 17:10:28 +0000
committerbors <bors@rust-lang.org>2025-06-22 17:10:28 +0000
commit111e9bc64bbdce14122e3676978f2ceefa5bff1a (patch)
tree28ed5aecce63ba1a3279eaa86a818cf899cd4dba /compiler
parentc2ec7532eed172e79800d28f087727c4b048badd (diff)
parent8da1a6290d0a097a497e109e70651c4f55e0fadb (diff)
downloadrust-111e9bc64bbdce14122e3676978f2ceefa5bff1a.tar.gz
rust-111e9bc64bbdce14122e3676978f2ceefa5bff1a.zip
Auto merge of #142878 - GuillaumeGomez:rollup-53dohob, r=GuillaumeGomez
Rollup of 10 pull requests

Successful merges:

 - rust-lang/rust#142458 (Merge unboxed trait object error suggestion into regular dyn incompat error)
 - rust-lang/rust#142593 (Add a warning to LateContext::get_def_path)
 - rust-lang/rust#142594 (Add DesugaringKind::FormatLiteral)
 - rust-lang/rust#142740 (Clean-up `FnCtxt::is_destruct_assignment_desugaring`)
 - rust-lang/rust#142780 (Port `#[must_use]` to new attribute parsing infrastructure)
 - rust-lang/rust#142798 (Don't fail to parse a struct if a semicolon is used to separate fields)
 - rust-lang/rust#142856 (Add a few inline directives in rustc_serialize.)
 - rust-lang/rust#142868 (remove few allow(dead_code))
 - rust-lang/rust#142874 (cranelift: fix target feature name typo: "fxsr")
 - rust-lang/rust#142877 (Document why tidy checks if `eslint` is installed via `npm`)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/format.rs8
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs9
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs40
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/sync/lock.rs2
-rw-r--r--compiler/rustc_data_structures/src/sync/parallel.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs25
-rw-r--r--compiler/rustc_lint/src/context.rs9
-rw-r--r--compiler/rustc_lint/src/unused.rs9
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs51
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs11
-rw-r--r--compiler/rustc_serialize/src/int_overflow.rs2
-rw-r--r--compiler/rustc_serialize/src/opaque.rs2
-rw-r--r--compiler/rustc_span/src/hygiene.rs16
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs39
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs2
27 files changed, 203 insertions, 133 deletions
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index b611ddea1d9..28d260419c5 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -50,6 +50,14 @@ pub struct FormatArgs {
     ///
     /// Generally only useful for lints that care about the raw bytes the user wrote.
     pub uncooked_fmt_str: (LitKind, Symbol),
+    /// Was the format literal written in the source?
+    /// - `format!("boo")` => true,
+    /// - `format!(concat!("b", "o", "o"))` => false,
+    /// - `format!(include_str!("boo.txt"))` => false,
+    ///
+    /// If it wasn't written in the source then we have to be careful with spans pointing into it
+    /// and suggestions about rewriting it.
+    pub is_source_literal: bool,
 }
 
 /// A piece of a format template string.
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1d437e5c2af..d0c2b2bf68b 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1566,7 +1566,7 @@ macro_rules! common_visitor_and_walkers {
 
         // FIXME: visit the template exhaustively.
         pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result {
-            let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
+            let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _, is_source_literal: _ } = fmt;
             let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ;
             for FormatArgument { kind, expr } in args {
                 match kind {
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 12f0af75486..943cde90dd2 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -4,7 +4,7 @@ use rustc_ast::*;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_session::config::FmtDebug;
-use rustc_span::{Ident, Span, Symbol, sym};
+use rustc_span::{DesugaringKind, Ident, Span, Symbol, sym};
 
 use super::LoweringContext;
 
@@ -14,6 +14,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // format_args!() had any arguments _before_ flattening/inlining.
         let allow_const = fmt.arguments.all_args().is_empty();
         let mut fmt = Cow::Borrowed(fmt);
+
+        let sp = self.mark_span_with_reason(
+            DesugaringKind::FormatLiteral { source: fmt.is_source_literal },
+            sp,
+            sp.ctxt().outer_expn_data().allow_internal_unstable,
+        );
+
         if self.tcx.sess.opts.unstable_opts.flatten_format_args {
             fmt = flatten_format_args(fmt);
             fmt = self.inline_literals(fmt);
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index f0f5cc4db07..ce1d8080262 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -237,6 +237,13 @@ pub enum AttributeKind {
     /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html).
     MayDangle(Span),
 
+    /// Represents `#[must_use]`.
+    MustUse {
+        span: Span,
+        /// must_use can optionally have a reason: `#[must_use = "reason this must be used"]`
+        reason: Option<Symbol>,
+    },
+
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 1bb5edba326..3162c1fc727 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -33,6 +33,7 @@ pub(crate) mod confusables;
 pub(crate) mod deprecation;
 pub(crate) mod inline;
 pub(crate) mod lint_helpers;
+pub(crate) mod must_use;
 pub(crate) mod repr;
 pub(crate) mod semantics;
 pub(crate) mod stability;
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
new file mode 100644
index 00000000000..a672d956127
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -0,0 +1,40 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_errors::DiagArgValue;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+use crate::session_diagnostics;
+
+pub(crate) struct MustUseParser;
+
+impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
+    const PATH: &[Symbol] = &[sym::must_use];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        Some(AttributeKind::MustUse {
+            span: cx.attr_span,
+            reason: match args {
+                ArgParser::NoArgs => None,
+                ArgParser::NameValue(name_value) => name_value.value_as_str(),
+                ArgParser::List(_) => {
+                    let suggestions =
+                        <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use");
+                    cx.emit_err(session_diagnostics::MustUseIllFormedAttributeInput {
+                        num_suggestions: suggestions.len(),
+                        suggestions: DiagArgValue::StrListSepByAnd(
+                            suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                        ),
+                        span: cx.attr_span,
+                    });
+                    return None;
+                }
+            },
+        })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index b95ea598e72..fbe874d606c 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -20,6 +20,7 @@ use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
 use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
+use crate::attributes::must_use::MustUseParser;
 use crate::attributes::repr::{AlignParser, ReprParser};
 use crate::attributes::semantics::MayDangleParser;
 use crate::attributes::stability::{
@@ -112,6 +113,7 @@ attribute_parsers!(
         Single<DeprecationParser>,
         Single<InlineParser>,
         Single<MayDangleParser>,
+        Single<MustUseParser>,
         Single<OptimizeParser>,
         Single<PubTransparentParser>,
         Single<RustcForceInlineParser>,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 29f2e44a98a..2a020770e5d 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -437,6 +437,15 @@ pub(crate) struct IllFormedAttributeInput {
 }
 
 #[derive(Diagnostic)]
+#[diag(attr_parsing_ill_formed_attribute_input)]
+pub(crate) struct MustUseIllFormedAttributeInput {
+    #[primary_span]
+    pub span: Span,
+    pub num_suggestions: usize,
+    pub suggestions: DiagArgValue,
+}
+
+#[derive(Diagnostic)]
 #[diag(attr_parsing_stability_outside_std, code = E0734)]
 pub(crate) struct StabilityOutsideStd {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 39f9d5f9005..6785cb6aef5 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -606,6 +606,7 @@ fn make_format_args(
         template,
         arguments: args,
         uncooked_fmt_str,
+        is_source_literal,
     }))
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 07ea29f3024..8e34436fb5e 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -184,7 +184,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
         // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
         let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" {
             // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
-            vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")]
+            vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")]
         } else if sess.target.arch == "aarch64" {
             match &*sess.target.os {
                 "none" => vec![],
diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs
index 2ccf06ccd4f..a8161c51511 100644
--- a/compiler/rustc_data_structures/src/sync/lock.rs
+++ b/compiler/rustc_data_structures/src/sync/lock.rs
@@ -1,8 +1,6 @@
 //! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
 //! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits.
 
-#![allow(dead_code)]
-
 use std::fmt;
 
 #[derive(Clone, Copy, PartialEq)]
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
index ff4b60a1031..b515c0bee8a 100644
--- a/compiler/rustc_data_structures/src/sync/parallel.rs
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -1,8 +1,6 @@
 //! This module defines parallel operations that are implemented in
 //! one way for the serial compiler, and another way the parallel compiler.
 
-#![allow(dead_code)]
-
 use std::any::Any;
 use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 13f95024e5a..d05e381f8c8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -382,8 +382,6 @@ fn check_trait_item<'tcx>(
         _ => (None, trait_item.span),
     };
 
-    check_dyn_incompatible_self_trait_by_name(tcx, trait_item);
-
     // Check that an item definition in a subtrait is shadowing a supertrait item.
     lint_item_shadowing_supertrait_item(tcx, def_id);
 
@@ -832,70 +830,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
     }
 }
 
-fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
-    match ty.kind {
-        hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
-            [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
-            _ => false,
-        },
-        _ => false,
-    }
-}
-
-/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items.
-///
-/// In such cases, suggest using `Self` instead.
-fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
-    let (trait_ident, trait_def_id) =
-        match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) {
-            hir::Node::Item(item) => match item.kind {
-                hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id),
-                _ => return,
-            },
-            _ => return,
-        };
-    let mut trait_should_be_self = vec![];
-    match &item.kind {
-        hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
-            if could_be_self(trait_def_id.def_id, ty) =>
-        {
-            trait_should_be_self.push(ty.span)
-        }
-        hir::TraitItemKind::Fn(sig, _) => {
-            for ty in sig.decl.inputs {
-                if could_be_self(trait_def_id.def_id, ty) {
-                    trait_should_be_self.push(ty.span);
-                }
-            }
-            match sig.decl.output {
-                hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
-                    trait_should_be_self.push(ty.span);
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
-    if !trait_should_be_self.is_empty() {
-        if tcx.is_dyn_compatible(trait_def_id) {
-            return;
-        }
-        let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
-        tcx.dcx()
-            .struct_span_err(
-                trait_should_be_self,
-                "associated item referring to unboxed trait object for its own trait",
-            )
-            .with_span_label(trait_ident.span, "in this trait")
-            .with_multipart_suggestion(
-                "you might have meant to use `Self` to refer to the implementing type",
-                sugg,
-                Applicability::MachineApplicable,
-            )
-            .emit();
-    }
-}
-
 fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) {
     let item_name = tcx.item_name(trait_item_def_id.to_def_id());
     let trait_def_id = tcx.local_parent(trait_item_def_id);
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 4633f3951a7..fef0dbf2ece 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -1,7 +1,8 @@
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::{ObligationCause, WellFormedLoc};
+use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions};
@@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>(
                     // over less-specific types (e.g. `Option<MyStruct<u8>>`)
                     if self.depth >= self.cause_depth {
                         self.cause = Some(error.obligation.cause);
+                        if let hir::TyKind::TraitObject(..) = ty.kind {
+                            if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
+                                self.tcx.def_kind(self.def_id)
+                            {
+                                self.cause = Some(ObligationCause::new(
+                                    ty.span,
+                                    self.def_id,
+                                    ObligationCauseCode::DynCompatible(ty.span),
+                                ));
+                            }
+                        }
                         self.cause_depth = self.depth
                     }
                 }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 5b55fbe9150..e5684f8cbe6 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1110,27 +1110,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    // Returns whether the given expression is a destruct assignment desugaring.
-    // For example, `(a, b) = (1, &2);`
-    // Here we try to find the pattern binding of the expression,
-    // `default_binding_modes` is false only for destruct assignment desugaring.
+    /// Returns whether the given expression is a destruct assignment desugaring.
+    /// For example, `(a, b) = (1, &2);`
+    /// Here we try to find the pattern binding of the expression,
+    /// `default_binding_modes` is false only for destruct assignment desugaring.
     pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
         if let hir::ExprKind::Path(hir::QPath::Resolved(
             _,
             hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
         )) = expr.kind
-        {
-            let bind = self.tcx.hir_node(*bind_hir_id);
-            let parent = self.tcx.parent_hir_node(*bind_hir_id);
-            if let hir::Node::Pat(hir::Pat {
+            && let bind = self.tcx.hir_node(*bind_hir_id)
+            && let parent = self.tcx.parent_hir_node(*bind_hir_id)
+            && let hir::Node::Pat(hir::Pat {
                 kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
             }) = bind
-                && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent
-            {
-                return true;
-            }
+            && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent
+        {
+            true
+        } else {
+            false
         }
-        false
     }
 
     fn explain_self_literal(
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 414f2a1846b..297b8ef7e76 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -711,6 +711,15 @@ impl<'tcx> LateContext<'tcx> {
 
     /// Gets the absolute path of `def_id` as a vector of `Symbol`.
     ///
+    /// Note that this is kinda expensive because it has to
+    /// travel the tree and pretty-print. Use sparingly.
+    ///
+    /// If you're trying to match for an item given by its path, use a
+    /// diagnostic item. If you're only interested in given sections, use more
+    /// specific functions, such as [`TyCtxt::crate_name`]
+    ///
+    /// FIXME: It would be great if this could be optimized.
+    ///
     /// # Examples
     ///
     /// ```rust,ignore (no context or def id available)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 1620f425794..a868c887493 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -2,6 +2,7 @@ use std::iter;
 
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::{MultiSpan, pluralize};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -368,10 +369,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         }
 
         fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
-            if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
+            if let Some(reason) = find_attr!(
+                cx.tcx.get_all_attrs(def_id),
+                AttributeKind::MustUse { reason, .. } => reason
+            ) {
                 // check for #[must_use = "..."]
-                let reason = attr.value_str();
-                Some(MustUsePath::Def(span, def_id, reason))
+                Some(MustUsePath::Def(span, def_id, *reason))
             } else {
                 None
             }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 27079af06fc..d877bd5c626 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -397,6 +397,8 @@ pub enum ObligationCauseCode<'tcx> {
 
     RustCall,
 
+    DynCompatible(Span),
+
     /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than
     /// the ADT it's being implemented for.
     AlwaysApplicableImpl,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 658ed4bd41c..5088caa80f8 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1781,7 +1781,7 @@ impl<'a> Parser<'a> {
         let mut recovered = Recovered::No;
         if self.eat(exp!(OpenBrace)) {
             while self.token != token::CloseBrace {
-                match self.parse_field_def(adt_ty) {
+                match self.parse_field_def(adt_ty, ident_span) {
                     Ok(field) => {
                         fields.push(field);
                     }
@@ -1894,7 +1894,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an element of a struct declaration.
-    fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
+    fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> {
         self.recover_vcs_conflict_marker();
         let attrs = self.parse_outer_attributes()?;
         self.recover_vcs_conflict_marker();
@@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> {
             let lo = this.token.span;
             let vis = this.parse_visibility(FollowedByType::No)?;
             let safety = this.parse_unsafe_field();
-            this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs)
+            this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span)
                 .map(|field| (field, Trailing::No, UsePreAttrPos::No))
         })
     }
@@ -1915,28 +1915,27 @@ impl<'a> Parser<'a> {
         vis: Visibility,
         safety: Safety,
         attrs: AttrVec,
+        ident_span: Span,
     ) -> PResult<'a, FieldDef> {
-        let mut seen_comma: bool = false;
         let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?;
-        if self.token == token::Comma {
-            seen_comma = true;
-        }
-        if self.eat(exp!(Semi)) {
-            let sp = self.prev_token.span;
-            let mut err =
-                self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
-            err.span_suggestion_short(
-                sp,
-                "replace `;` with `,`",
-                ",",
-                Applicability::MachineApplicable,
-            );
-            return Err(err);
-        }
         match self.token.kind {
             token::Comma => {
                 self.bump();
             }
+            token::Semi => {
+                self.bump();
+                let sp = self.prev_token.span;
+                let mut err =
+                    self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
+                err.span_suggestion_short(
+                    sp,
+                    "replace `;` with `,`",
+                    ",",
+                    Applicability::MachineApplicable,
+                );
+                err.span_label(ident_span, format!("while parsing this {adt_ty}"));
+                err.emit();
+            }
             token::CloseBrace => {}
             token::DocComment(..) => {
                 let previous_span = self.prev_token.span;
@@ -1945,19 +1944,11 @@ impl<'a> Parser<'a> {
                     missing_comma: None,
                 };
                 self.bump(); // consume the doc comment
-                let comma_after_doc_seen = self.eat(exp!(Comma));
-                // `seen_comma` is always false, because we are inside doc block
-                // condition is here to make code more readable
-                if !seen_comma && comma_after_doc_seen {
-                    seen_comma = true;
-                }
-                if comma_after_doc_seen || self.token == token::CloseBrace {
+                if self.eat(exp!(Comma)) || self.token == token::CloseBrace {
                     self.dcx().emit_err(err);
                 } else {
-                    if !seen_comma {
-                        let sp = previous_span.shrink_to_hi();
-                        err.missing_comma = Some(sp);
-                    }
+                    let sp = previous_span.shrink_to_hi();
+                    err.missing_comma = Some(sp);
                     return Err(self.dcx().create_err(err));
                 }
             }
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index ed1737bee33..8e6442353c3 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -293,6 +293,7 @@ fn emit_malformed_attribute(
             | sym::deprecated
             | sym::optimize
             | sym::cold
+            | sym::must_use
     ) {
         return;
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d802bf4df19..e11ec2ed47a 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -171,6 +171,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
                     self.check_may_dangle(hir_id, *attr_span)
                 }
+                Attribute::Parsed(AttributeKind::MustUse { span, .. }) => {
+                    self.check_must_use(hir_id, *span, target)
+                }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
                     match attr.path().as_slice() {
@@ -245,7 +248,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
                         [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
                         [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
-                        [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
                         [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
                         [sym::rustc_allow_incoherent_impl, ..] => {
                             self.check_allow_incoherent_impl(attr, span, target)
@@ -696,7 +698,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             AttributeKind::Deprecation { .. }
                             | AttributeKind::Repr { .. }
                             | AttributeKind::Align { .. }
-                            | AttributeKind::Cold(..),
+                            | AttributeKind::Cold(..)
+                            | AttributeKind::MustUse { .. },
                         ) => {
                             continue;
                         }
@@ -1576,7 +1579,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Warns against some misuses of `#[must_use]`
-    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+    fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) {
         if matches!(
             target,
             Target::Fn
@@ -1616,7 +1619,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span(),
+            attr_span,
             errors::MustUseNoEffect { article, target },
         );
     }
diff --git a/compiler/rustc_serialize/src/int_overflow.rs b/compiler/rustc_serialize/src/int_overflow.rs
index f2aac2ef711..6782fbc33da 100644
--- a/compiler/rustc_serialize/src/int_overflow.rs
+++ b/compiler/rustc_serialize/src/int_overflow.rs
@@ -20,6 +20,7 @@ macro_rules! impl_debug_strict_add {
     ($( $ty:ty )*) => {
         $(
             impl DebugStrictAdd for $ty {
+                #[inline]
                 fn debug_strict_add(self, other: Self) -> Self {
                     if cfg!(debug_assertions) {
                         self + other
@@ -42,6 +43,7 @@ macro_rules! impl_debug_strict_sub {
     ($( $ty:ty )*) => {
         $(
             impl DebugStrictSub for $ty {
+                #[inline]
                 fn debug_strict_sub(self, other: Self) -> Self {
                     if cfg!(debug_assertions) {
                         self - other
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 00bad8e70cf..4242642c664 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -89,10 +89,12 @@ impl FileEncoder {
         self.buffered = 0;
     }
 
+    #[inline]
     pub fn file(&self) -> &File {
         &self.file
     }
 
+    #[inline]
     pub fn path(&self) -> &Path {
         &self.path
     }
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 315dedec107..29be3b73ee9 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1213,6 +1213,17 @@ pub enum DesugaringKind {
     Contract,
     /// A pattern type range start/end
     PatTyRange,
+    /// A format literal.
+    FormatLiteral {
+        /// Was this format literal written in the source?
+        /// - `format!("boo")` => Yes,
+        /// - `format!(concat!("b", "o", "o"))` => No,
+        /// - `format!(include_str!("boo.txt"))` => No,
+        ///
+        /// If it wasn't written in the source then we have to be careful with suggestions about
+        /// rewriting it.
+        source: bool,
+    },
 }
 
 impl DesugaringKind {
@@ -1231,6 +1242,10 @@ impl DesugaringKind {
             DesugaringKind::BoundModifier => "trait bound modifier",
             DesugaringKind::Contract => "contract check",
             DesugaringKind::PatTyRange => "pattern type",
+            DesugaringKind::FormatLiteral { source: true } => "format string literal",
+            DesugaringKind::FormatLiteral { source: false } => {
+                "expression that expanded into a format string literal"
+            }
         }
     }
 
@@ -1250,6 +1265,7 @@ impl DesugaringKind {
             DesugaringKind::BoundModifier => value == "BoundModifier",
             DesugaringKind::Contract => value == "Contract",
             DesugaringKind::PatTyRange => value == "PatTyRange",
+            DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index da69f6c4492..684b1781b44 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1080,7 +1080,6 @@ symbols! {
         fs_create_dir,
         fsub_algebraic,
         fsub_fast,
-        fsxr,
         full,
         fundamental,
         fused_iterator,
@@ -1088,6 +1087,7 @@ symbols! {
         future_drop_poll,
         future_output,
         future_trait,
+        fxsr,
         gdb_script_file,
         ge,
         gen_blocks,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 6d07ae021ae..2bbf90ed3ed 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2721,6 +2721,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
+            ObligationCauseCode::DynCompatible(span) => {
+                err.multipart_suggestion(
+                    "you might have meant to use `Self` to refer to the implementing type",
+                    vec![(span, "Self".into())],
+                    Applicability::MachineApplicable,
+                );
+            }
             ObligationCauseCode::WhereClause(item_def_id, span)
             | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
             | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..)
@@ -2872,13 +2879,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         _ => (),
                     }
                 }
-                let descr = format!("required by {a} bound in `{item_name}`");
-                if span.is_visible(sm) {
-                    let msg = format!("required by {this} in `{short_item_name}`");
-                    multispan.push_span_label(span, msg);
-                    err.span_note(multispan, descr);
+
+                // If this is from a format string literal desugaring,
+                // we've already said "required by this formatting parameter"
+                let is_in_fmt_lit = if let Some(s) = err.span.primary_span() {
+                    matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. }))
                 } else {
-                    err.span_note(tcx.def_span(item_def_id), descr);
+                    false
+                };
+                if !is_in_fmt_lit {
+                    let descr = format!("required by {a} bound in `{item_name}`");
+                    if span.is_visible(sm) {
+                        let msg = format!("required by {this} in `{short_item_name}`");
+                        multispan.push_span_label(span, msg);
+                        err.span_note(multispan, descr);
+                    } else {
+                        err.span_note(tcx.def_span(item_def_id), descr);
+                    }
                 }
                 if let Some(note) = note {
                     err.note(note);
@@ -3973,7 +3990,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ) = expr.kind
             {
                 if Some(*span) != err.span.primary_span() {
-                    err.span_label(*span, "required by a bound introduced by this call");
+                    let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true })
+                    {
+                        "required by this formatting parameter"
+                    } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) {
+                        "required by a formatting parameter in this expression"
+                    } else {
+                        "required by a bound introduced by this call"
+                    };
+                    err.span_label(*span, msg);
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index ee30956295a..bdfe48a3928 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -31,7 +31,7 @@ use crate::traits::{
 ///
 /// Currently that is `Self` in supertraits. This is needed
 /// because `dyn_compatibility_violations` can't be used during
-/// type collection.
+/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself.
 #[instrument(level = "debug", skip(tcx), ret)]
 pub fn hir_ty_lowering_dyn_compatibility_violations(
     tcx: TyCtxt<'_>,