about summary refs log tree commit diff
path: root/compiler/rustc_lint/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-17 11:18:57 +0000
committerbors <bors@rust-lang.org>2024-10-17 11:18:57 +0000
commite09bf4c07af8a424f9022bfe8d42ec714a51f0be (patch)
tree0aa83217a4da4a550ed80601e35381bb06db1c33 /compiler/rustc_lint/src
parentecf6fc5336a7fe24607b8c394f34a4fcd20079c8 (diff)
parent6e4f8fea36cd04f623c46d99adc3c370b1879883 (diff)
downloadrust-e09bf4c07af8a424f9022bfe8d42ec714a51f0be.tar.gz
rust-e09bf4c07af8a424f9022bfe8d42ec714a51f0be.zip
Auto merge of #18317 - lnicola:sync-from-rust, r=Veykril
minor: sync from downstream
Diffstat (limited to 'compiler/rustc_lint/src')
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs3
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs10
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs94
-rw-r--r--compiler/rustc_lint/src/traits.rs5
-rw-r--r--compiler/rustc_lint/src/unused.rs10
6 files changed, 86 insertions, 38 deletions
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index b5ab56912cb..565c3c04252 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -176,6 +176,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
             lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
                 .decorate_lint(diag);
         }
+        BuiltinLintDiag::ReservedString(suggestion) => {
+            lints::ReservedString { suggestion }.decorate_lint(diag);
+        }
         BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
             lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag);
         }
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index cdd0e80c458..58fd11fcc29 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -24,7 +24,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,edition2021
-    /// #![cfg_attr(not(bootstrap), feature(if_let_rescope))] // Simplify this in bootstrap bump.
+    /// #![feature(if_let_rescope)]
     /// #![warn(if_let_rescope)]
     /// #![allow(unused_variables)]
     ///
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index a861894a444..16cfae17d40 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1430,8 +1430,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
                         );
                     }
                 }
-
-                diag.note(fluent::lint_non_local_definitions_deprecation);
             }
             NonLocalDefinitionsDiag::MacroRules {
                 depth,
@@ -1452,7 +1450,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
                 }
 
                 diag.note(fluent::lint_non_local);
-                diag.note(fluent::lint_non_local_definitions_deprecation);
 
                 if let Some(cargo_update) = cargo_update {
                     diag.subdiagnostic(cargo_update);
@@ -3053,3 +3050,10 @@ pub(crate) enum MutRefSugg {
 #[derive(LintDiagnostic)]
 #[diag(lint_unqualified_local_imports)]
 pub(crate) struct UnqualifiedLocalImportsDiag {}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_reserved_string)]
+pub(crate) struct ReservedString {
+    #[suggestion(code = " ", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 56f930ea7f6..3c31b879bd6 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -124,16 +124,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 // If that's the case this means that this impl block declaration
                 // is using local items and so we don't lint on it.
 
-                // We also ignore anon-const in item by including the anon-const
-                // parent as well.
-                let parent_parent = if parent_def_kind == DefKind::Const
-                    && parent_opt_item_name == Some(kw::Underscore)
-                {
-                    Some(cx.tcx.parent(parent))
-                } else {
-                    None
-                };
-
                 // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
                 // of the `impl` definition
                 let mut collector = PathCollector { paths: Vec::new() };
@@ -148,13 +138,33 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                     |p| matches!(p.res, Res::Def(def_kind, _) if def_kind != DefKind::TyParam),
                 );
 
-                // 2. We check if any of path reference a "local" parent and if that the case
-                // we bail out as asked by T-lang, even though this isn't correct from a
-                // type-system point of view, as inference exists and could still leak the impl.
+                // 1.9. We retrieve the parent def id of the impl item, ...
+                //
+                // ... modulo const-anons items, for enhanced compatibility with the ecosystem
+                // as that pattern is common with `serde`, `bevy`, ...
+                //
+                // For this example we want the `DefId` parent of the outermost const-anon items.
+                // ```
+                // const _: () = { // the parent of this const-anon
+                //     const _: () = {
+                //         impl Foo {}
+                //     };
+                // };
+                // ```
+                let outermost_impl_parent = peel_parent_while(cx.tcx, parent, |tcx, did| {
+                    tcx.def_kind(did) == DefKind::Const
+                        && tcx.opt_item_name(did) == Some(kw::Underscore)
+                });
+
+                // 2. We check if any of the paths reference a the `impl`-parent.
+                //
+                // If that the case we bail out, as was asked by T-lang, even though this isn't
+                // correct from a type-system point of view, as inference exists and one-impl-rule
+                // make its so that we could still leak the impl.
                 if collector
                     .paths
                     .iter()
-                    .any(|path| path_has_local_parent(path, cx, parent, parent_parent))
+                    .any(|path| path_has_local_parent(path, cx, parent, outermost_impl_parent))
                 {
                     return;
                 }
@@ -253,8 +263,8 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
     }
 }
 
-/// Given a path and a parent impl def id, this checks if the if parent resolution
-/// def id correspond to the def id of the parent impl definition.
+/// Given a path, this checks if the if the parent resolution def id corresponds to
+/// the def id of the parent impl definition (the direct one and the outermost one).
 ///
 /// Given this path, we will look at the path (and ignore any generic args):
 ///
@@ -267,32 +277,54 @@ fn path_has_local_parent(
     path: &Path<'_>,
     cx: &LateContext<'_>,
     impl_parent: DefId,
-    impl_parent_parent: Option<DefId>,
+    outermost_impl_parent: Option<DefId>,
 ) -> bool {
     path.res
         .opt_def_id()
-        .is_some_and(|did| did_has_local_parent(did, cx.tcx, impl_parent, impl_parent_parent))
+        .is_some_and(|did| did_has_local_parent(did, cx.tcx, impl_parent, outermost_impl_parent))
 }
 
-/// Given a def id and a parent impl def id, this checks if the parent
-/// def id (modulo modules) correspond to the def id of the parent impl definition.
+/// Given a def id this checks if the parent def id (modulo modules) correspond to
+/// the def id of the parent impl definition (the direct one and the outermost one).
 #[inline]
 fn did_has_local_parent(
     did: DefId,
     tcx: TyCtxt<'_>,
     impl_parent: DefId,
-    impl_parent_parent: Option<DefId>,
+    outermost_impl_parent: Option<DefId>,
 ) -> bool {
-    did.is_local()
-        && if let Some(did_parent) = tcx.opt_parent(did) {
-            did_parent == impl_parent
-                || Some(did_parent) == impl_parent_parent
-                || !did_parent.is_crate_root()
-                    && tcx.def_kind(did_parent) == DefKind::Mod
-                    && did_has_local_parent(did_parent, tcx, impl_parent, impl_parent_parent)
-        } else {
-            false
-        }
+    if !did.is_local() {
+        return false;
+    }
+
+    let Some(parent_did) = tcx.opt_parent(did) else {
+        return false;
+    };
+
+    peel_parent_while(tcx, parent_did, |tcx, did| {
+        tcx.def_kind(did) == DefKind::Mod
+            || (tcx.def_kind(did) == DefKind::Const
+                && tcx.opt_item_name(did) == Some(kw::Underscore))
+    })
+    .map(|parent_did| parent_did == impl_parent || Some(parent_did) == outermost_impl_parent)
+    .unwrap_or(false)
+}
+
+/// Given a `DefId` checks if it satisfies `f` if it does check with it's parent and continue
+/// until it doesn't satisfies `f` and return the last `DefId` checked.
+///
+/// In other word this method return the first `DefId` that doesn't satisfies `f`.
+#[inline]
+fn peel_parent_while(
+    tcx: TyCtxt<'_>,
+    mut did: DefId,
+    mut f: impl FnMut(TyCtxt<'_>, DefId) -> bool,
+) -> Option<DefId> {
+    while !did.is_crate_root() && f(tcx, did) {
+        did = tcx.opt_parent(did).filter(|parent_did| parent_did.is_local())?;
+    }
+
+    Some(did)
 }
 
 /// Return for a given `Path` the span until the last args
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index c0a01b0065e..5a3666dcbd4 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -112,10 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
 
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
         let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
-        for (bound, modifier) in &bounds[..] {
+        for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
             if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
-                && *modifier != hir::TraitBoundModifier::Maybe
+                // FIXME: ?Drop is not a thing.
+                && bound.modifiers != hir::TraitBoundModifier::Maybe
             {
                 let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
                 cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 12d5b5cf979..1a007250961 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -804,7 +804,15 @@ trait UnusedDelimLint {
                 .find_ancestor_inside(value.span)
                 .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
             ast::ExprKind::Paren(ref expr) => {
-                expr.span.find_ancestor_inside(value.span).map(|expr_span| {
+                // For the expr with attributes, like `let _ = (#[inline] || println!("Hello!"));`,
+                // the span should contains the attributes, or the suggestion will remove them.
+                let expr_span_with_attrs =
+                    if let Some(attr_lo) = expr.attrs.iter().map(|attr| attr.span.lo()).min() {
+                        expr.span.with_lo(attr_lo)
+                    } else {
+                        expr.span
+                    };
+                expr_span_with_attrs.find_ancestor_inside(value.span).map(|expr_span| {
                     (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))
                 })
             }