about summary refs log tree commit diff
path: root/compiler/rustc_lint/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src')
-rw-r--r--compiler/rustc_lint/src/builtin.rs78
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs3
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs16
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs6
-rw-r--r--compiler/rustc_lint/src/levels.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs10
-rw-r--r--compiler/rustc_lint/src/lifetime_syntax.rs149
-rw-r--r--compiler/rustc_lint/src/lints.rs95
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs9
-rw-r--r--compiler/rustc_lint/src/types/literal.rs42
-rw-r--r--compiler/rustc_lint/src/unused.rs10
13 files changed, 302 insertions, 122 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 172f3372483..8244f0bed4c 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -28,7 +28,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_hir::intravisit::FnKind as HirFnKind;
-use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin};
+use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin};
 use rustc_middle::bug;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::ty::layout::LayoutOf;
@@ -952,36 +952,34 @@ declare_lint! {
 
 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
 
+impl InvalidNoMangleItems {
+    fn check_no_mangle_on_generic_fn(
+        &self,
+        cx: &LateContext<'_>,
+        attr_span: Span,
+        def_id: LocalDefId,
+    ) {
+        let generics = cx.tcx.generics_of(def_id);
+        if generics.requires_monomorphization(cx.tcx) {
+            cx.emit_span_lint(
+                NO_MANGLE_GENERIC_ITEMS,
+                cx.tcx.def_span(def_id),
+                BuiltinNoMangleGeneric { suggestion: attr_span },
+            );
+        }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         let attrs = cx.tcx.hir_attrs(it.hir_id());
-        let check_no_mangle_on_generic_fn = |attr_span: Span,
-                                             impl_generics: Option<&hir::Generics<'_>>,
-                                             generics: &hir::Generics<'_>,
-                                             span| {
-            for param in
-                generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
-            {
-                match param.kind {
-                    GenericParamKind::Lifetime { .. } => {}
-                    GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                        cx.emit_span_lint(
-                            NO_MANGLE_GENERIC_ITEMS,
-                            span,
-                            BuiltinNoMangleGeneric { suggestion: attr_span },
-                        );
-                        break;
-                    }
-                }
-            }
-        };
         match it.kind {
-            hir::ItemKind::Fn { generics, .. } => {
+            hir::ItemKind::Fn { .. } => {
                 if let Some(attr_span) =
                     find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
                         .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
                 {
-                    check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
+                    self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id);
                 }
             }
             hir::ItemKind::Const(..) => {
@@ -1006,24 +1004,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     );
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
-                for it in *items {
-                    if let hir::AssocItemKind::Fn { .. } = it.kind {
-                        let attrs = cx.tcx.hir_attrs(it.id.hir_id());
-                        if let Some(attr_span) =
-                            find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
-                                .or_else(
-                                    || find_attr!(attrs, AttributeKind::NoMangle(span) => *span),
-                                )
-                        {
-                            check_no_mangle_on_generic_fn(
-                                attr_span,
-                                Some(generics),
-                                cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
-                                it.span,
-                            );
-                        }
-                    }
+            _ => {}
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'_>, it: &hir::ImplItem<'_>) {
+        let attrs = cx.tcx.hir_attrs(it.hir_id());
+        match it.kind {
+            hir::ImplItemKind::Fn { .. } => {
+                if let Some(attr_span) =
+                    find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
+                        .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
+                {
+                    self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id);
                 }
             }
             _ => {}
@@ -1526,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     ClauseKind::TypeOutlives(..) |
                     ClauseKind::RegionOutlives(..) => "lifetime",
 
+                    ClauseKind::UnstableFeature(_)
                     // `ConstArgHasType` is never global as `ct` is always a param
-                    ClauseKind::ConstArgHasType(..)
+                    | ClauseKind::ConstArgHasType(..)
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
                     | ClauseKind::Projection(..)
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index 0bc772d081f..b5fc083a095 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -1,3 +1,4 @@
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
@@ -62,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
         let hir::ImplItemKind::Fn(_sig, body_id) = impl_item.kind else { return };
         let assoc = cx.tcx.associated_item(impl_item.owner_id);
         let parent = assoc.container_id(cx.tcx);
-        if cx.tcx.has_attr(parent, sym::automatically_derived) {
+        if find_attr!(cx.tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) {
             // We don't care about what `#[derive(Default)]` produces in this lint.
             return;
         }
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 5989ef9519c..dd16117db1c 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -1,7 +1,7 @@
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::sym;
+use rustc_span::{Ident, sym};
 use rustc_trait_selection::traits::supertraits;
 
 use crate::lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel};
@@ -79,11 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
             // erase regions in self type for better diagnostic presentation
             let (self_ty, target_principal, supertrait_principal) =
                 tcx.erase_regions((self_ty, target_principal, supertrait_principal));
-            let label2 = impl_
-                .items
-                .iter()
-                .find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
-                .map(|label| SupertraitAsDerefTargetLabel { label });
+            let label2 = tcx
+                .associated_items(item.owner_id)
+                .find_by_ident_and_kind(
+                    tcx,
+                    Ident::with_dummy_span(sym::Target),
+                    ty::AssocTag::Type,
+                    item.owner_id.to_def_id(),
+                )
+                .map(|label| SupertraitAsDerefTargetLabel { label: tcx.def_span(label.def_id) });
             let span = tcx.def_span(item.owner_id.def_id);
             cx.emit_span_lint(
                 DEREF_INTO_DYN_SUPERTRAIT,
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 3b0a36186b6..f0fbf5bc81e 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -1,6 +1,3 @@
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::untranslatable_diagnostic)]
-
 use std::borrow::Cow;
 
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
@@ -354,6 +351,9 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
+        BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => {
+            lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag);
+        }
         BuiltinLintDiag::UnusedQualifications { removal_span } => {
             lints::UnusedQualifications { removal_span }.decorate_lint(diag);
         }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index c72f8571153..16eeb89207b 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -644,7 +644,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
     ) {
         let sess = self.sess;
         for (attr_index, attr) in attrs.iter().enumerate() {
-            if attr.has_name(sym::automatically_derived) {
+            if attr.is_automatically_derived_attr() {
                 self.insert(
                     LintId::of(SINGLE_USE_LIFETIMES),
                     LevelAndSource {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 48982bda0a0..f06757b3c23 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,7 +55,7 @@ mod invalid_from_utf8;
 mod late;
 mod let_underscore;
 mod levels;
-mod lifetime_syntax;
+pub mod lifetime_syntax;
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
@@ -339,6 +339,14 @@ fn register_builtins(store: &mut LintStore) {
 
     add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024);
 
+    add_lint_group!(
+        "unknown_or_malformed_diagnostic_attributes",
+        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+        MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
+        MISPLACED_DIAGNOSTIC_ATTRIBUTES,
+        UNKNOWN_DIAGNOSTIC_ATTRIBUTES
+    );
+
     // Register renamed and removed lints.
     store.register_renamed("single_use_lifetime", "single_use_lifetimes");
     store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 5465968e984..2a5a34cdc6e 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
     }
 }
 
-fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
-    // Categorize lifetimes into source/syntax buckets.
-    let mut n_hidden = 0;
-    let mut n_elided = 0;
-    let mut n_named = 0;
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum LifetimeSyntaxCategory {
+    Hidden,
+    Elided,
+    Named,
+}
 
-    for info in input_info.iter().chain(output_info) {
+impl LifetimeSyntaxCategory {
+    fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> {
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
-
         match syntax_source {
-            // Ignore any other kind of lifetime.
-            (_, Other) => continue,
-
             // E.g. `&T`.
-            (Implicit, Reference | OutlivesBound | PreciseCapturing) |
+            (Implicit, Reference) |
             // E.g. `&'_ T`.
-            (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitAnonymous, Reference) |
             // E.g. `ContainsLifetime<'_>`.
-            (ExplicitAnonymous, Path { .. }) => n_elided += 1,
+            (ExplicitAnonymous, Path { .. }) |
+            // E.g. `+ '_`, `+ use<'_>`.
+            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Elided)
+            }
 
             // E.g. `ContainsLifetime`.
-            (Implicit, Path { .. }) => n_hidden += 1,
+            (Implicit, Path { .. }) => {
+                Some(Self::Hidden)
+            }
 
             // E.g. `&'a T`.
-            (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitBound, Reference) |
             // E.g. `ContainsLifetime<'a>`.
-            (ExplicitBound, Path { .. }) => n_named += 1,
-        };
+            (ExplicitBound, Path { .. }) |
+            // E.g. `+ 'a`, `+ use<'a>`.
+            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Named)
+            }
+
+            (Implicit, OutlivesBound | PreciseCapturing) |
+            (_, Other) => {
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug, Default)]
+pub struct LifetimeSyntaxCategories<T> {
+    pub hidden: T,
+    pub elided: T,
+    pub named: T,
+}
+
+impl<T> LifetimeSyntaxCategories<T> {
+    fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T {
+        use LifetimeSyntaxCategory::*;
+
+        match category {
+            Elided => &mut self.elided,
+            Hidden => &mut self.hidden,
+            Named => &mut self.named,
+        }
+    }
+}
+
+impl<T> LifetimeSyntaxCategories<Vec<T>> {
+    pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
+        LifetimeSyntaxCategories {
+            hidden: self.hidden.len(),
+            elided: self.elided.len(),
+            named: self.named.len(),
+        }
+    }
+
+    pub fn flatten(&self) -> impl Iterator<Item = &T> {
+        let Self { hidden, elided, named } = self;
+        [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten()
+    }
+}
+
+impl std::ops::Add for LifetimeSyntaxCategories<usize> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Self {
+            hidden: self.hidden + rhs.hidden,
+            elided: self.elided + rhs.elided,
+            named: self.named + rhs.named,
+        }
+    }
+}
+
+fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
+    let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default();
+
+    for info in input_info.iter().chain(output_info) {
+        if let Some(category) = info.lifetime_syntax_category() {
+            *syntax_counts.select(category) += 1;
+        }
     }
 
-    let syntax_counts = (n_hidden, n_elided, n_named);
     tracing::debug!(?syntax_counts);
 
-    matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _))
+    matches!(
+        syntax_counts,
+        LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ }
+    )
 }
 
 fn emit_mismatch_diagnostic<'tcx>(
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
+        let syntax_source = info.syntax_source();
 
         if let (_, Other) = syntax_source {
             // Ignore any other kind of lifetime.
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
             // E.g. `&'_ T`.
             (ExplicitAnonymous, Reference) => {
                 suggest_change_to_implicit.push(info);
-                suggest_change_to_mixed_implicit.push(info);
                 suggest_change_to_explicit_bound.push(info);
             }
 
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
         }
     }
 
+    let categorize = |infos: &[Info<'_>]| {
+        let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
+        for info in infos {
+            if let Some(category) = info.lifetime_syntax_category() {
+                categories.select(category).push(info.reporting_span());
+            }
+        }
+        categories
+    };
+
+    let inputs = categorize(input_info);
+    let outputs = categorize(output_info);
+
     let make_implicit_suggestions =
         |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
 
-    let inputs = input_info.iter().map(|info| info.reporting_span()).collect();
-    let outputs = output_info.iter().map(|info| info.reporting_span()).collect();
-
     let explicit_bound_suggestion = bound_lifetime.map(|info| {
         build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
     });
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
         ?explicit_anonymous_suggestion,
     );
 
-    let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned();
-
     // We can produce a number of suggestions which may overwhelm
     // the user. Instead, we order the suggestions based on Rust
     // idioms. The "best" choice is shown to the user and the
@@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>(
 
     cx.emit_span_lint(
         MISMATCHED_LIFETIME_SYNTAXES,
-        Vec::clone(&inputs),
-        lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions },
+        inputs.flatten().copied().collect::<Vec<_>>(),
+        lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions },
     );
 }
 
@@ -422,12 +501,12 @@ fn build_mismatch_suggestion(
     lifetime_name: &str,
     infos: &[&Info<'_>],
 ) -> lints::MismatchedLifetimeSyntaxesSuggestion {
-    let lifetime_name_sugg = lifetime_name.to_owned();
+    let lifetime_name = lifetime_name.to_owned();
 
     let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
 
     lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
-        lifetime_name_sugg,
+        lifetime_name,
         suggestions,
         tool_only: false,
     }
@@ -441,6 +520,14 @@ struct Info<'tcx> {
 }
 
 impl<'tcx> Info<'tcx> {
+    fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) {
+        (self.lifetime.syntax, self.lifetime.source)
+    }
+
+    fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> {
+        LifetimeSyntaxCategory::new(self.syntax_source())
+    }
+
     fn lifetime_name(&self) -> &str {
         self.lifetime.ident.as_str()
     }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 5e05b58146e..fd8d0f832aa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1,4 +1,3 @@
-#![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 use std::num::NonZero;
 
@@ -22,6 +21,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
 
 use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
 use crate::errors::{OverruledAttributeSub, RequestedLevel};
+use crate::lifetime_syntax::LifetimeSyntaxCategories;
 use crate::{LateContext, fluent_generated as fluent};
 
 // array_into_iter.rs
@@ -1748,6 +1748,20 @@ pub(crate) struct OverflowingLiteral<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_surrogate_char_cast)]
+#[note]
+pub(crate) struct SurrogateCharCast {
+    pub literal: u128,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_too_large_char_cast)]
+#[note]
+pub(crate) struct TooLargeCharCast {
+    pub literal: u128,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_uses_power_alignment)]
 pub(crate) struct UsesPowerAlignment;
 
@@ -3082,6 +3096,14 @@ pub(crate) struct HiddenGlobReexports {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_reexport_private_dependency)]
+pub(crate) struct ReexportPrivateDependency {
+    pub name: String,
+    pub kind: String,
+    pub krate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unnecessary_qualification)]
 pub(crate) struct UnusedQualifications {
     #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
@@ -3195,31 +3217,60 @@ pub(crate) struct ReservedMultihash {
 
 #[derive(Debug)]
 pub(crate) struct MismatchedLifetimeSyntaxes {
-    pub lifetime_name: String,
-    pub inputs: Vec<Span>,
-    pub outputs: Vec<Span>,
+    pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
+    pub outputs: LifetimeSyntaxCategories<Vec<Span>>,
 
     pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
 }
 
 impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
     fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
-        diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes);
+        let counts = self.inputs.len() + self.outputs.len();
+        let message = match counts {
+            LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => {
+                panic!("No lifetime mismatch detected")
+            }
 
-        diag.arg("lifetime_name", self.lifetime_name);
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named
+            }
+        };
+        diag.primary_message(message);
 
-        diag.arg("n_inputs", self.inputs.len());
-        for input in self.inputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs);
-            diag.span_label(input, a);
+        for s in self.inputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden);
+        }
+        for s in self.inputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided);
+        }
+        for s in self.inputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named);
         }
 
-        diag.arg("n_outputs", self.outputs.len());
-        for output in self.outputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs);
-            diag.span_label(output, a);
+        for s in self.outputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden);
+        }
+        for s in self.outputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided);
+        }
+        for s in self.outputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named);
         }
 
+        diag.help(fluent::lint_mismatched_lifetime_syntaxes_help);
+
         let mut suggestions = self.suggestions.into_iter();
         if let Some(s) = suggestions.next() {
             diag.subdiagnostic(s);
@@ -3246,7 +3297,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
     },
 
     Explicit {
-        lifetime_name_sugg: String,
+        lifetime_name: String,
         suggestions: Vec<(Span, String)>,
         tool_only: bool,
     },
@@ -3286,6 +3337,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
             }
 
             Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
+                let message = if implicit_suggestions.is_empty() {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
+                } else {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed
+                };
+
                 let implicit_suggestions =
                     implicit_suggestions.into_iter().map(|s| (s, String::new()));
 
@@ -3293,19 +3350,19 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
                     implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
 
                 diag.multipart_suggestion_with_style(
-                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
+                    message,
                     suggestions,
                     Applicability::MaybeIncorrect,
                     style(tool_only),
                 );
             }
 
-            Explicit { lifetime_name_sugg, suggestions, tool_only } => {
-                diag.arg("lifetime_name_sugg", lifetime_name_sugg);
+            Explicit { lifetime_name, suggestions, tool_only } => {
+                diag.arg("lifetime_name", lifetime_name);
                 let msg = diag.eagerly_translate(
                     fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
                 );
-                diag.remove_arg("lifetime_name_sugg");
+                diag.remove_arg("lifetime_name");
                 diag.multipart_suggestion_with_style(
                     msg,
                     suggestions,
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 3cc55eaa0f2..5513c703f1d 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
         let def_id = item.owner_id.to_def_id();
         // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
         // the latter will report `where_clause_object_safety` lint.
-        if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind
+        if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind
             && cx.tcx.is_dyn_compatible(def_id)
         {
             let direct_super_traits_iter = cx
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index bc9badbb232..db89396d1dc 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -167,7 +167,7 @@ impl NonCamelCaseTypes {
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = matches!(
-            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id),
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None),
             Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
         );
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index e41bc8f852e..fc9d795cb23 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -59,8 +59,7 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `overflowing_literals` lint detects literal out of range for its
-    /// type.
+    /// The `overflowing_literals` lint detects literals out of range for their type.
     ///
     /// ### Example
     ///
@@ -72,9 +71,9 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// It is usually a mistake to use a literal that overflows the type where
-    /// it is used. Either use a literal that is within range, or change the
-    /// type to be within the range of the literal.
+    /// It is usually a mistake to use a literal that overflows its type
+    /// Change either the literal or its type such that the literal is
+    /// within the range of its type.
     OVERFLOWING_LITERALS,
     Deny,
     "literal out of range for its type"
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index d44f45177bd..2bac58ba23d 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -12,7 +12,7 @@ use crate::context::LintContext;
 use crate::lints::{
     OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
     OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
-    RangeEndpointOutOfRange, UseInclusiveRange,
+    RangeEndpointOutOfRange, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange,
 };
 use crate::types::{OVERFLOWING_LITERALS, TypeLimits};
 
@@ -38,12 +38,18 @@ fn lint_overflowing_range_endpoint<'tcx>(
 
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
-    let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false };
-    let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
+    let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else {
+        return false;
+    };
+    let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else {
+        return false;
+    };
     if !is_range_literal(struct_expr) {
         return false;
     };
-    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
+    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else {
+        return false;
+    };
 
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
@@ -61,7 +67,9 @@ fn lint_overflowing_range_endpoint<'tcx>(
     };
 
     let sub_sugg = if span.lo() == lit_span.lo() {
-        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
+        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else {
+            return false;
+        };
         UseInclusiveRange::WithoutParen {
             sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
             start,
@@ -316,11 +324,25 @@ fn lint_uint_literal<'tcx>(
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
-                        cx.emit_span_lint(
-                            OVERFLOWING_LITERALS,
-                            par_e.span,
-                            OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
-                        );
+                        if lit_val > 0x10FFFF {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                TooLargeCharCast { literal: lit_val },
+                            );
+                        } else if (0xD800..=0xDFFF).contains(&lit_val) {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                SurrogateCharCast { literal: lit_val },
+                            );
+                        } else {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
+                            );
+                        }
                         return;
                     }
                 }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index d3942a1c816..a9eb1739f7f 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1,7 +1,7 @@
 use std::iter;
 
 use rustc_ast::util::{classify, parser};
-use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
+use rustc_ast::{self as ast, ExprKind, FnRetTy, HasAttrs as _, StmtKind};
 use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{MultiSpan, pluralize};
@@ -599,6 +599,7 @@ enum UnusedDelimsCtx {
     AnonConst,
     MatchArmExpr,
     IndexExpr,
+    ClosureBody,
 }
 
 impl From<UnusedDelimsCtx> for &'static str {
@@ -620,6 +621,7 @@ impl From<UnusedDelimsCtx> for &'static str {
             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
             UnusedDelimsCtx::MatchArmExpr => "match arm expression",
             UnusedDelimsCtx::IndexExpr => "index expression",
+            UnusedDelimsCtx::ClosureBody => "closure body",
         }
     }
 }
@@ -919,6 +921,11 @@ trait UnusedDelimLint {
                 let (args_to_check, ctx) = match *call_or_other {
                     Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
                     MethodCall(ref call) => (&call.args[..], UnusedDelimsCtx::MethodArg),
+                    Closure(ref closure)
+                        if matches!(closure.fn_decl.output, FnRetTy::Default(_)) =>
+                    {
+                        (&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody)
+                    }
                     // actual catch-all arm
                     _ => {
                         return;
@@ -1508,6 +1515,7 @@ impl UnusedDelimLint for UnusedBraces {
                             && (ctx != UnusedDelimsCtx::AnonConst
                                 || (matches!(expr.kind, ast::ExprKind::Lit(_))
                                     && !expr.span.from_expansion()))
+                            && ctx != UnusedDelimsCtx::ClosureBody
                             && !cx.sess().source_map().is_multiline(value.span)
                             && value.attrs.is_empty()
                             && !value.span.from_expansion()