rustc_lint/
builtin.rs

1//! Lints in the Rust compiler.
2//!
3//! This contains lints which can feasibly be implemented as their own
4//! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
5//! definitions of lints that are emitted directly inside the main compiler.
6//!
7//! To add a new lint to rustc, declare it here using [`declare_lint!`].
8//! Then add code to emit the new lint in the appropriate circumstances.
9//!
10//! If you define a new [`EarlyLintPass`], you will also need to add it to the
11//! [`crate::early_lint_methods!`] invocation in `lib.rs`.
12//!
13//! If you define a new [`LateLintPass`], you will also need to add it to the
14//! [`crate::late_lint_methods!`] invocation in `lib.rs`.
15
16use std::fmt::Write;
17
18use ast::token::TokenKind;
19use rustc_abi::BackendRepr;
20use rustc_ast::tokenstream::{TokenStream, TokenTree};
21use rustc_ast::visit::{FnCtxt, FnKind};
22use rustc_ast::{self as ast, *};
23use rustc_ast_pretty::pprust::expr_to_string;
24use rustc_errors::{Applicability, LintDiagnostic};
25use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
26use rustc_hir as hir;
27use rustc_hir::def::{DefKind, Res};
28use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
29use rustc_hir::intravisit::FnKind as HirFnKind;
30use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin};
31use rustc_middle::bug;
32use rustc_middle::lint::LevelAndSource;
33use rustc_middle::ty::layout::LayoutOf;
34use rustc_middle::ty::print::with_no_trimmed_paths;
35use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
36use rustc_session::lint::FutureIncompatibilityReason;
37// hardwired lints from rustc_lint_defs
38pub use rustc_session::lint::builtin::*;
39use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
40use rustc_span::edition::Edition;
41use rustc_span::source_map::Spanned;
42use rustc_span::{BytePos, Ident, InnerSpan, Span, Symbol, kw, sym};
43use rustc_target::asm::InlineAsmArch;
44use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
45use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;
46use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
47use rustc_trait_selection::traits::{self};
48
49use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
50use crate::lints::{
51    BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
52    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
53    BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
54    BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
55    BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
56    BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
57    BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
58    BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
59    BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
60    BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
61    BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
62};
63use crate::nonstandard_style::{MethodLateContext, method_context};
64use crate::{
65    EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
66    fluent_generated as fluent,
67};
68declare_lint! {
69    /// The `while_true` lint detects `while true { }`.
70    ///
71    /// ### Example
72    ///
73    /// ```rust,no_run
74    /// while true {
75    ///
76    /// }
77    /// ```
78    ///
79    /// {{produces}}
80    ///
81    /// ### Explanation
82    ///
83    /// `while true` should be replaced with `loop`. A `loop` expression is
84    /// the preferred way to write an infinite loop because it more directly
85    /// expresses the intent of the loop.
86    WHILE_TRUE,
87    Warn,
88    "suggest using `loop { }` instead of `while true { }`"
89}
90
91declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
92
93impl EarlyLintPass for WhileTrue {
94    #[inline]
95    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
96        if let ast::ExprKind::While(cond, _, label) = &e.kind
97            && let ast::ExprKind::Lit(token_lit) = cond.peel_parens().kind
98            && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
99            && !cond.span.from_expansion()
100        {
101            let condition_span = e.span.with_hi(cond.span.hi());
102            let replace = format!(
103                "{}loop",
104                label.map_or_else(String::new, |label| format!("{}: ", label.ident,))
105            );
106            cx.emit_span_lint(
107                WHILE_TRUE,
108                condition_span,
109                BuiltinWhileTrue { suggestion: condition_span, replace },
110            );
111        }
112    }
113}
114
115declare_lint! {
116    /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
117    /// instead of `Struct { x }` in a pattern.
118    ///
119    /// ### Example
120    ///
121    /// ```rust
122    /// struct Point {
123    ///     x: i32,
124    ///     y: i32,
125    /// }
126    ///
127    ///
128    /// fn main() {
129    ///     let p = Point {
130    ///         x: 5,
131    ///         y: 5,
132    ///     };
133    ///
134    ///     match p {
135    ///         Point { x: x, y: y } => (),
136    ///     }
137    /// }
138    /// ```
139    ///
140    /// {{produces}}
141    ///
142    /// ### Explanation
143    ///
144    /// The preferred style is to avoid the repetition of specifying both the
145    /// field name and the binding name if both identifiers are the same.
146    NON_SHORTHAND_FIELD_PATTERNS,
147    Warn,
148    "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
149}
150
151declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
152
153impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
154    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
155        if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
156            let variant = cx
157                .typeck_results()
158                .pat_ty(pat)
159                .ty_adt_def()
160                .expect("struct pattern type is not an ADT")
161                .variant_of_res(cx.qpath_res(qpath, pat.hir_id));
162            for fieldpat in field_pats {
163                if fieldpat.is_shorthand {
164                    continue;
165                }
166                if fieldpat.span.from_expansion() {
167                    // Don't lint if this is a macro expansion: macro authors
168                    // shouldn't have to worry about this kind of style issue
169                    // (Issue #49588)
170                    continue;
171                }
172                if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
173                    if cx.tcx.find_field_index(ident, variant)
174                        == Some(cx.typeck_results().field_index(fieldpat.hir_id))
175                    {
176                        cx.emit_span_lint(
177                            NON_SHORTHAND_FIELD_PATTERNS,
178                            fieldpat.span,
179                            BuiltinNonShorthandFieldPatterns {
180                                ident,
181                                suggestion: fieldpat.span,
182                                prefix: binding_annot.prefix_str(),
183                            },
184                        );
185                    }
186                }
187            }
188        }
189    }
190}
191
192declare_lint! {
193    /// The `unsafe_code` lint catches usage of `unsafe` code and other
194    /// potentially unsound constructs like `no_mangle`, `export_name`,
195    /// and `link_section`.
196    ///
197    /// ### Example
198    ///
199    /// ```rust,compile_fail
200    /// #![deny(unsafe_code)]
201    /// fn main() {
202    ///     unsafe {
203    ///
204    ///     }
205    /// }
206    ///
207    /// #[no_mangle]
208    /// fn func_0() { }
209    ///
210    /// #[export_name = "exported_symbol_name"]
211    /// pub fn name_in_rust() { }
212    ///
213    /// #[no_mangle]
214    /// #[link_section = ".example_section"]
215    /// pub static VAR1: u32 = 1;
216    /// ```
217    ///
218    /// {{produces}}
219    ///
220    /// ### Explanation
221    ///
222    /// This lint is intended to restrict the usage of `unsafe` blocks and other
223    /// constructs (including, but not limited to `no_mangle`, `link_section`
224    /// and `export_name` attributes) wrong usage of which causes undefined
225    /// behavior.
226    UNSAFE_CODE,
227    Allow,
228    "usage of `unsafe` code and other potentially unsound constructs",
229    @eval_always = true
230}
231
232declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
233
234impl UnsafeCode {
235    fn report_unsafe(
236        &self,
237        cx: &EarlyContext<'_>,
238        span: Span,
239        decorate: impl for<'a> LintDiagnostic<'a, ()>,
240    ) {
241        // This comes from a macro that has `#[allow_internal_unsafe]`.
242        if span.allows_unsafe() {
243            return;
244        }
245
246        cx.emit_span_lint(UNSAFE_CODE, span, decorate);
247    }
248}
249
250impl EarlyLintPass for UnsafeCode {
251    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
252        if attr.has_name(sym::allow_internal_unsafe) {
253            self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
254        }
255    }
256
257    #[inline]
258    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
259        if let ast::ExprKind::Block(ref blk, _) = e.kind {
260            // Don't warn about generated blocks; that'll just pollute the output.
261            if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
262                self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock);
263            }
264        }
265    }
266
267    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
268        match it.kind {
269            ast::ItemKind::Trait(box ast::Trait { safety: ast::Safety::Unsafe(_), .. }) => {
270                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
271            }
272
273            ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => {
274                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
275            }
276
277            ast::ItemKind::Fn(..) => {
278                if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
279                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
280                }
281
282                if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
283                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
284                }
285
286                if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
287                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
288                }
289            }
290
291            ast::ItemKind::Static(..) => {
292                if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
293                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
294                }
295
296                if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
297                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
298                }
299
300                if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
301                    self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
302                }
303            }
304
305            ast::ItemKind::GlobalAsm(..) => {
306                self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm);
307            }
308
309            ast::ItemKind::ForeignMod(ForeignMod { safety, .. }) => {
310                if let Safety::Unsafe(_) = safety {
311                    self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeExternBlock);
312                }
313            }
314
315            _ => {}
316        }
317    }
318
319    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
320        if let ast::AssocItemKind::Fn(..) = it.kind {
321            if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
322                self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
323            }
324            if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
325                self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
326            }
327        }
328    }
329
330    fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
331        if let FnKind::Fn(
332            ctxt,
333            _,
334            ast::Fn {
335                sig: ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
336                body,
337                ..
338            },
339        ) = fk
340        {
341            let decorator = match ctxt {
342                FnCtxt::Foreign => return,
343                FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn,
344                FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod,
345                FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod,
346            };
347            self.report_unsafe(cx, span, decorator);
348        }
349    }
350}
351
352declare_lint! {
353    /// The `missing_docs` lint detects missing documentation for public items.
354    ///
355    /// ### Example
356    ///
357    /// ```rust,compile_fail
358    /// #![deny(missing_docs)]
359    /// pub fn foo() {}
360    /// ```
361    ///
362    /// {{produces}}
363    ///
364    /// ### Explanation
365    ///
366    /// This lint is intended to ensure that a library is well-documented.
367    /// Items without documentation can be difficult for users to understand
368    /// how to use properly.
369    ///
370    /// This lint is "allow" by default because it can be noisy, and not all
371    /// projects may want to enforce everything to be documented.
372    pub MISSING_DOCS,
373    Allow,
374    "detects missing documentation for public members",
375    report_in_external_macro
376}
377
378#[derive(Default)]
379pub struct MissingDoc;
380
381impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
382
383fn has_doc(attr: &hir::Attribute) -> bool {
384    if attr.is_doc_comment() {
385        return true;
386    }
387
388    if !attr.has_name(sym::doc) {
389        return false;
390    }
391
392    if attr.value_str().is_some() {
393        return true;
394    }
395
396    if let Some(list) = attr.meta_item_list() {
397        for meta in list {
398            if meta.has_name(sym::hidden) {
399                return true;
400            }
401        }
402    }
403
404    false
405}
406
407impl MissingDoc {
408    fn check_missing_docs_attrs(
409        &self,
410        cx: &LateContext<'_>,
411        def_id: LocalDefId,
412        article: &'static str,
413        desc: &'static str,
414    ) {
415        // Only check publicly-visible items, using the result from the privacy pass.
416        // It's an option so the crate root can also use this function (it doesn't
417        // have a `NodeId`).
418        if def_id != CRATE_DEF_ID && !cx.effective_visibilities.is_exported(def_id) {
419            return;
420        }
421
422        let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id));
423        let has_doc = attrs.iter().any(has_doc);
424        if !has_doc {
425            cx.emit_span_lint(
426                MISSING_DOCS,
427                cx.tcx.def_span(def_id),
428                BuiltinMissingDoc { article, desc },
429            );
430        }
431    }
432}
433
434impl<'tcx> LateLintPass<'tcx> for MissingDoc {
435    fn check_crate(&mut self, cx: &LateContext<'_>) {
436        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
437    }
438
439    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
440        // Previously the Impl and Use types have been excluded from missing docs,
441        // so we will continue to exclude them for compatibility.
442        //
443        // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
444        if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) =
445            it.kind
446        {
447            return;
448        }
449
450        let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
451        self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
452    }
453
454    fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
455        let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
456
457        self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
458    }
459
460    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
461        let context = method_context(cx, impl_item.owner_id.def_id);
462
463        match context {
464            // If the method is an impl for a trait, don't doc.
465            MethodLateContext::TraitImpl => return,
466            MethodLateContext::TraitAutoImpl => {}
467            // If the method is an impl for an item with docs_hidden, don't doc.
468            MethodLateContext::PlainImpl => {
469                let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id());
470                let impl_ty = cx.tcx.type_of(parent).instantiate_identity();
471                let outerdef = match impl_ty.kind() {
472                    ty::Adt(def, _) => Some(def.did()),
473                    ty::Foreign(def_id) => Some(*def_id),
474                    _ => None,
475                };
476                let is_hidden = match outerdef {
477                    Some(id) => cx.tcx.is_doc_hidden(id),
478                    None => false,
479                };
480                if is_hidden {
481                    return;
482                }
483            }
484        }
485
486        let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
487        self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
488    }
489
490    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
491        let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
492        self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
493    }
494
495    fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
496        if !sf.is_positional() {
497            self.check_missing_docs_attrs(cx, sf.def_id, "a", "struct field")
498        }
499    }
500
501    fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
502        self.check_missing_docs_attrs(cx, v.def_id, "a", "variant");
503    }
504}
505
506declare_lint! {
507    /// The `missing_copy_implementations` lint detects potentially-forgotten
508    /// implementations of [`Copy`] for public types.
509    ///
510    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
511    ///
512    /// ### Example
513    ///
514    /// ```rust,compile_fail
515    /// #![deny(missing_copy_implementations)]
516    /// pub struct Foo {
517    ///     pub field: i32
518    /// }
519    /// # fn main() {}
520    /// ```
521    ///
522    /// {{produces}}
523    ///
524    /// ### Explanation
525    ///
526    /// Historically (before 1.0), types were automatically marked as `Copy`
527    /// if possible. This was changed so that it required an explicit opt-in
528    /// by implementing the `Copy` trait. As part of this change, a lint was
529    /// added to alert if a copyable type was not marked `Copy`.
530    ///
531    /// This lint is "allow" by default because this code isn't bad; it is
532    /// common to write newtypes like this specifically so that a `Copy` type
533    /// is no longer `Copy`. `Copy` types can result in unintended copies of
534    /// large data which can impact performance.
535    pub MISSING_COPY_IMPLEMENTATIONS,
536    Allow,
537    "detects potentially-forgotten implementations of `Copy`"
538}
539
540declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
541
542impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
543    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
544        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
545            return;
546        }
547        let (def, ty) = match item.kind {
548            hir::ItemKind::Struct(_, _, ast_generics) => {
549                if !ast_generics.params.is_empty() {
550                    return;
551                }
552                let def = cx.tcx.adt_def(item.owner_id);
553                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
554            }
555            hir::ItemKind::Union(_, _, ast_generics) => {
556                if !ast_generics.params.is_empty() {
557                    return;
558                }
559                let def = cx.tcx.adt_def(item.owner_id);
560                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
561            }
562            hir::ItemKind::Enum(_, _, ast_generics) => {
563                if !ast_generics.params.is_empty() {
564                    return;
565                }
566                let def = cx.tcx.adt_def(item.owner_id);
567                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
568            }
569            _ => return,
570        };
571        if def.has_dtor(cx.tcx) {
572            return;
573        }
574
575        // If the type contains a raw pointer, it may represent something like a handle,
576        // and recommending Copy might be a bad idea.
577        for field in def.all_fields() {
578            let did = field.did;
579            if cx.tcx.type_of(did).instantiate_identity().is_raw_ptr() {
580                return;
581            }
582        }
583        if cx.type_is_copy_modulo_regions(ty) {
584            return;
585        }
586        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) {
587            return;
588        }
589        if def.is_variant_list_non_exhaustive()
590            || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive())
591        {
592            return;
593        }
594
595        // We shouldn't recommend implementing `Copy` on stateful things,
596        // such as iterators.
597        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
598            && cx
599                .tcx
600                .infer_ctxt()
601                .build(cx.typing_mode())
602                .type_implements_trait(iter_trait, [ty], cx.param_env)
603                .must_apply_modulo_regions()
604        {
605            return;
606        }
607
608        // Default value of clippy::trivially_copy_pass_by_ref
609        const MAX_SIZE: u64 = 256;
610
611        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {
612            if size > MAX_SIZE {
613                return;
614            }
615        }
616
617        if type_allowed_to_implement_copy(
618            cx.tcx,
619            cx.param_env,
620            ty,
621            traits::ObligationCause::misc(item.span, item.owner_id.def_id),
622            hir::Safety::Safe,
623        )
624        .is_ok()
625        {
626            cx.emit_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl);
627        }
628    }
629}
630
631/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.
632fn type_implements_negative_copy_modulo_regions<'tcx>(
633    tcx: TyCtxt<'tcx>,
634    ty: Ty<'tcx>,
635    typing_env: ty::TypingEnv<'tcx>,
636) -> bool {
637    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
638    let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
639    let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };
640    let obligation = traits::Obligation {
641        cause: traits::ObligationCause::dummy(),
642        param_env,
643        recursion_depth: 0,
644        predicate: pred.upcast(tcx),
645    };
646    infcx.predicate_must_hold_modulo_regions(&obligation)
647}
648
649declare_lint! {
650    /// The `missing_debug_implementations` lint detects missing
651    /// implementations of [`fmt::Debug`] for public types.
652    ///
653    /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
654    ///
655    /// ### Example
656    ///
657    /// ```rust,compile_fail
658    /// #![deny(missing_debug_implementations)]
659    /// pub struct Foo;
660    /// # fn main() {}
661    /// ```
662    ///
663    /// {{produces}}
664    ///
665    /// ### Explanation
666    ///
667    /// Having a `Debug` implementation on all types can assist with
668    /// debugging, as it provides a convenient way to format and display a
669    /// value. Using the `#[derive(Debug)]` attribute will automatically
670    /// generate a typical implementation, or a custom implementation can be
671    /// added by manually implementing the `Debug` trait.
672    ///
673    /// This lint is "allow" by default because adding `Debug` to all types can
674    /// have a negative impact on compile time and code size. It also requires
675    /// boilerplate to be added to every type, which can be an impediment.
676    MISSING_DEBUG_IMPLEMENTATIONS,
677    Allow,
678    "detects missing implementations of Debug"
679}
680
681#[derive(Default)]
682pub(crate) struct MissingDebugImplementations;
683
684impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
685
686impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
687    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
688        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
689            return;
690        }
691
692        match item.kind {
693            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
694            _ => return,
695        }
696
697        // Avoid listing trait impls if the trait is allowed.
698        let LevelAndSource { level, .. } =
699            cx.tcx.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id());
700        if level == Level::Allow {
701            return;
702        }
703
704        let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
705
706        let has_impl = cx
707            .tcx
708            .non_blanket_impls_for_ty(debug, cx.tcx.type_of(item.owner_id).instantiate_identity())
709            .next()
710            .is_some();
711        if !has_impl {
712            cx.emit_span_lint(
713                MISSING_DEBUG_IMPLEMENTATIONS,
714                item.span,
715                BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug },
716            );
717        }
718    }
719}
720
721declare_lint! {
722    /// The `anonymous_parameters` lint detects anonymous parameters in trait
723    /// definitions.
724    ///
725    /// ### Example
726    ///
727    /// ```rust,edition2015,compile_fail
728    /// #![deny(anonymous_parameters)]
729    /// // edition 2015
730    /// pub trait Foo {
731    ///     fn foo(usize);
732    /// }
733    /// fn main() {}
734    /// ```
735    ///
736    /// {{produces}}
737    ///
738    /// ### Explanation
739    ///
740    /// This syntax is mostly a historical accident, and can be worked around
741    /// quite easily by adding an `_` pattern or a descriptive identifier:
742    ///
743    /// ```rust
744    /// trait Foo {
745    ///     fn foo(_: usize);
746    /// }
747    /// ```
748    ///
749    /// This syntax is now a hard error in the 2018 edition. In the 2015
750    /// edition, this lint is "warn" by default. This lint
751    /// enables the [`cargo fix`] tool with the `--edition` flag to
752    /// automatically transition old code from the 2015 edition to 2018. The
753    /// tool will run this lint and automatically apply the
754    /// suggested fix from the compiler (which is to add `_` to each
755    /// parameter). This provides a completely automated way to update old
756    /// code for a new edition. See [issue #41686] for more details.
757    ///
758    /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
759    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
760    pub ANONYMOUS_PARAMETERS,
761    Warn,
762    "detects anonymous parameters",
763    @future_incompatible = FutureIncompatibleInfo {
764        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
765        reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
766    };
767}
768
769declare_lint_pass!(
770    /// Checks for use of anonymous parameters (RFC 1685).
771    AnonymousParameters => [ANONYMOUS_PARAMETERS]
772);
773
774impl EarlyLintPass for AnonymousParameters {
775    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
776        if cx.sess().edition() != Edition::Edition2015 {
777            // This is a hard error in future editions; avoid linting and erroring
778            return;
779        }
780        if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
781            for arg in sig.decl.inputs.iter() {
782                if let ast::PatKind::Missing = arg.pat.kind {
783                    let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
784
785                    let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
786                        (snip.as_str(), Applicability::MachineApplicable)
787                    } else {
788                        ("<type>", Applicability::HasPlaceholders)
789                    };
790                    cx.emit_span_lint(
791                        ANONYMOUS_PARAMETERS,
792                        arg.pat.span,
793                        BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
794                    );
795                }
796            }
797        }
798    }
799}
800
801/// Check for use of attributes which have been deprecated.
802#[derive(Clone)]
803pub struct DeprecatedAttr {
804    // This is not free to compute, so we want to keep it around, rather than
805    // compute it for every attribute.
806    depr_attrs: Vec<&'static BuiltinAttribute>,
807}
808
809impl_lint_pass!(DeprecatedAttr => []);
810
811impl Default for DeprecatedAttr {
812    fn default() -> Self {
813        DeprecatedAttr { depr_attrs: deprecated_attributes() }
814    }
815}
816
817impl EarlyLintPass for DeprecatedAttr {
818    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
819        for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
820            if attr.ident().map(|ident| ident.name) == Some(*name) {
821                if let &AttributeGate::Gated(
822                    Stability::Deprecated(link, suggestion),
823                    name,
824                    reason,
825                    _,
826                ) = gate
827                {
828                    let suggestion = match suggestion {
829                        Some(msg) => {
830                            BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
831                        }
832                        None => {
833                            BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
834                        }
835                    };
836                    cx.emit_span_lint(
837                        DEPRECATED,
838                        attr.span,
839                        BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
840                    );
841                }
842                return;
843            }
844        }
845    }
846}
847
848fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
849    use rustc_ast::token::CommentKind;
850
851    let mut attrs = attrs.iter().peekable();
852
853    // Accumulate a single span for sugared doc comments.
854    let mut sugared_span: Option<Span> = None;
855
856    while let Some(attr) = attrs.next() {
857        let is_doc_comment = attr.is_doc_comment();
858        if is_doc_comment {
859            sugared_span =
860                Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
861        }
862
863        if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) {
864            continue;
865        }
866
867        let span = sugared_span.take().unwrap_or(attr.span);
868
869        if is_doc_comment || attr.has_name(sym::doc) {
870            let sub = match attr.kind {
871                AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
872                    BuiltinUnusedDocCommentSub::PlainHelp
873                }
874                AttrKind::DocComment(CommentKind::Block, _) => {
875                    BuiltinUnusedDocCommentSub::BlockHelp
876                }
877            };
878            cx.emit_span_lint(
879                UNUSED_DOC_COMMENTS,
880                span,
881                BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub },
882            );
883        }
884    }
885}
886
887impl EarlyLintPass for UnusedDocComment {
888    fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
889        let kind = match stmt.kind {
890            ast::StmtKind::Let(..) => "statements",
891            // Disabled pending discussion in #78306
892            ast::StmtKind::Item(..) => return,
893            // expressions will be reported by `check_expr`.
894            ast::StmtKind::Empty
895            | ast::StmtKind::Semi(_)
896            | ast::StmtKind::Expr(_)
897            | ast::StmtKind::MacCall(_) => return,
898        };
899
900        warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
901    }
902
903    fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
904        if let Some(body) = &arm.body {
905            let arm_span = arm.pat.span.with_hi(body.span.hi());
906            warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
907        }
908    }
909
910    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
911        if let ast::PatKind::Struct(_, _, fields, _) = &pat.kind {
912            for field in fields {
913                warn_if_doc(cx, field.span, "pattern fields", &field.attrs);
914            }
915        }
916    }
917
918    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
919        warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
920
921        if let ExprKind::Struct(s) = &expr.kind {
922            for field in &s.fields {
923                warn_if_doc(cx, field.span, "expression fields", &field.attrs);
924            }
925        }
926    }
927
928    fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
929        warn_if_doc(cx, param.ident.span, "generic parameters", &param.attrs);
930    }
931
932    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
933        warn_if_doc(cx, block.span, "blocks", block.attrs());
934    }
935
936    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
937        if let ast::ItemKind::ForeignMod(_) = item.kind {
938            warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
939        }
940    }
941}
942
943declare_lint! {
944    /// The `no_mangle_const_items` lint detects any `const` items with the
945    /// [`no_mangle` attribute].
946    ///
947    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
948    ///
949    /// ### Example
950    ///
951    /// ```rust,compile_fail,edition2021
952    /// #[no_mangle]
953    /// const FOO: i32 = 5;
954    /// ```
955    ///
956    /// {{produces}}
957    ///
958    /// ### Explanation
959    ///
960    /// Constants do not have their symbols exported, and therefore, this
961    /// probably means you meant to use a [`static`], not a [`const`].
962    ///
963    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
964    /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
965    NO_MANGLE_CONST_ITEMS,
966    Deny,
967    "const items will not have their symbols exported"
968}
969
970declare_lint! {
971    /// The `no_mangle_generic_items` lint detects generic items that must be
972    /// mangled.
973    ///
974    /// ### Example
975    ///
976    /// ```rust
977    /// #[unsafe(no_mangle)]
978    /// fn foo<T>(t: T) {}
979    /// ```
980    ///
981    /// {{produces}}
982    ///
983    /// ### Explanation
984    ///
985    /// A function with generics must have its symbol mangled to accommodate
986    /// the generic parameter. The [`no_mangle` attribute] has no effect in
987    /// this situation, and should be removed.
988    ///
989    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
990    NO_MANGLE_GENERIC_ITEMS,
991    Warn,
992    "generic items must be mangled"
993}
994
995declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
996
997impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
998    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
999        let attrs = cx.tcx.hir_attrs(it.hir_id());
1000        let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute,
1001                                             impl_generics: Option<&hir::Generics<'_>>,
1002                                             generics: &hir::Generics<'_>,
1003                                             span| {
1004            for param in
1005                generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1006            {
1007                match param.kind {
1008                    GenericParamKind::Lifetime { .. } => {}
1009                    GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1010                        cx.emit_span_lint(
1011                            NO_MANGLE_GENERIC_ITEMS,
1012                            span,
1013                            BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() },
1014                        );
1015                        break;
1016                    }
1017                }
1018            }
1019        };
1020        match it.kind {
1021            hir::ItemKind::Fn { generics, .. } => {
1022                if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
1023                    check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
1024                }
1025            }
1026            hir::ItemKind::Const(..) => {
1027                if attr::contains_name(attrs, sym::no_mangle) {
1028                    // account for "pub const" (#45562)
1029                    let start = cx
1030                        .tcx
1031                        .sess
1032                        .source_map()
1033                        .span_to_snippet(it.span)
1034                        .map(|snippet| snippet.find("const").unwrap_or(0))
1035                        .unwrap_or(0) as u32;
1036                    // `const` is 5 chars
1037                    let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1038
1039                    // Const items do not refer to a particular location in memory, and therefore
1040                    // don't have anything to attach a symbol to
1041                    cx.emit_span_lint(
1042                        NO_MANGLE_CONST_ITEMS,
1043                        it.span,
1044                        BuiltinConstNoMangle { suggestion },
1045                    );
1046                }
1047            }
1048            hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1049                for it in *items {
1050                    if let hir::AssocItemKind::Fn { .. } = it.kind {
1051                        if let Some(no_mangle_attr) =
1052                            attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle)
1053                        {
1054                            check_no_mangle_on_generic_fn(
1055                                no_mangle_attr,
1056                                Some(generics),
1057                                cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
1058                                it.span,
1059                            );
1060                        }
1061                    }
1062                }
1063            }
1064            _ => {}
1065        }
1066    }
1067}
1068
1069declare_lint! {
1070    /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1071    /// T` because it is [undefined behavior].
1072    ///
1073    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1074    ///
1075    /// ### Example
1076    ///
1077    /// ```rust,compile_fail
1078    /// unsafe {
1079    ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);
1080    /// }
1081    /// ```
1082    ///
1083    /// {{produces}}
1084    ///
1085    /// ### Explanation
1086    ///
1087    /// Certain assumptions are made about aliasing of data, and this transmute
1088    /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1089    ///
1090    /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1091    MUTABLE_TRANSMUTES,
1092    Deny,
1093    "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1094}
1095
1096declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1097
1098impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1099    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1100        if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =
1101            get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1102        {
1103            if from_mutbl < to_mutbl {
1104                cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
1105            }
1106        }
1107
1108        fn get_transmute_from_to<'tcx>(
1109            cx: &LateContext<'tcx>,
1110            expr: &hir::Expr<'_>,
1111        ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1112            let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1113                cx.qpath_res(qpath, expr.hir_id)
1114            } else {
1115                return None;
1116            };
1117            if let Res::Def(DefKind::Fn, did) = def {
1118                if !def_id_is_transmute(cx, did) {
1119                    return None;
1120                }
1121                let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1122                let from = sig.inputs().skip_binder()[0];
1123                let to = sig.output().skip_binder();
1124                return Some((from, to));
1125            }
1126            None
1127        }
1128
1129        fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1130            cx.tcx.is_intrinsic(def_id, sym::transmute)
1131        }
1132    }
1133}
1134
1135declare_lint! {
1136    /// The `unstable_features` lint detects uses of `#![feature]`.
1137    ///
1138    /// ### Example
1139    ///
1140    /// ```rust,compile_fail
1141    /// #![deny(unstable_features)]
1142    /// #![feature(test)]
1143    /// ```
1144    ///
1145    /// {{produces}}
1146    ///
1147    /// ### Explanation
1148    ///
1149    /// In larger nightly-based projects which
1150    ///
1151    /// * consist of a multitude of crates where a subset of crates has to compile on
1152    ///   stable either unconditionally or depending on a `cfg` flag to for example
1153    ///   allow stable users to depend on them,
1154    /// * don't use nightly for experimental features but for, e.g., unstable options only,
1155    ///
1156    /// this lint may come in handy to enforce policies of these kinds.
1157    UNSTABLE_FEATURES,
1158    Allow,
1159    "enabling unstable features"
1160}
1161
1162declare_lint_pass!(
1163    /// Forbids using the `#[feature(...)]` attribute
1164    UnstableFeatures => [UNSTABLE_FEATURES]
1165);
1166
1167impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1168    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
1169        if attr.has_name(sym::feature)
1170            && let Some(items) = attr.meta_item_list()
1171        {
1172            for item in items {
1173                cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
1174            }
1175        }
1176    }
1177}
1178
1179declare_lint! {
1180    /// The `ungated_async_fn_track_caller` lint warns when the
1181    /// `#[track_caller]` attribute is used on an async function
1182    /// without enabling the corresponding unstable feature flag.
1183    ///
1184    /// ### Example
1185    ///
1186    /// ```rust
1187    /// #[track_caller]
1188    /// async fn foo() {}
1189    /// ```
1190    ///
1191    /// {{produces}}
1192    ///
1193    /// ### Explanation
1194    ///
1195    /// The attribute must be used in conjunction with the
1196    /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`
1197    /// annotation will function as a no-op.
1198    ///
1199    /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html
1200    UNGATED_ASYNC_FN_TRACK_CALLER,
1201    Warn,
1202    "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"
1203}
1204
1205declare_lint_pass!(
1206    /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to
1207    /// do anything
1208    UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER]
1209);
1210
1211impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
1212    fn check_fn(
1213        &mut self,
1214        cx: &LateContext<'_>,
1215        fn_kind: HirFnKind<'_>,
1216        _: &'tcx FnDecl<'_>,
1217        _: &'tcx Body<'_>,
1218        span: Span,
1219        def_id: LocalDefId,
1220    ) {
1221        if fn_kind.asyncness().is_async()
1222            && !cx.tcx.features().async_fn_track_caller()
1223            // Now, check if the function has the `#[track_caller]` attribute
1224            && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
1225        {
1226            cx.emit_span_lint(
1227                UNGATED_ASYNC_FN_TRACK_CALLER,
1228                attr.span(),
1229                BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
1230            );
1231        }
1232    }
1233}
1234
1235declare_lint! {
1236    /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that
1237    /// means neither directly accessible, nor reexported (with `pub use`), nor leaked through
1238    /// things like return types (which the [`unnameable_types`] lint can detect if desired).
1239    ///
1240    /// ### Example
1241    ///
1242    /// ```rust,compile_fail
1243    /// #![deny(unreachable_pub)]
1244    /// mod foo {
1245    ///     pub mod bar {
1246    ///
1247    ///     }
1248    /// }
1249    /// ```
1250    ///
1251    /// {{produces}}
1252    ///
1253    /// ### Explanation
1254    ///
1255    /// The `pub` keyword both expresses an intent for an item to be publicly available, and also
1256    /// signals to the compiler to make the item publicly accessible. The intent can only be
1257    /// satisfied, however, if all items which contain this item are *also* publicly accessible.
1258    /// Thus, this lint serves to identify situations where the intent does not match the reality.
1259    ///
1260    /// If you wish the item to be accessible elsewhere within the crate, but not outside it, the
1261    /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the
1262    /// intent that the item is only visible within its own crate.
1263    ///
1264    /// This lint is "allow" by default because it will trigger for a large amount of existing Rust code.
1265    /// Eventually it is desired for this to become warn-by-default.
1266    ///
1267    /// [`unnameable_types`]: #unnameable-types
1268    pub UNREACHABLE_PUB,
1269    Allow,
1270    "`pub` items not reachable from crate root"
1271}
1272
1273declare_lint_pass!(
1274    /// Lint for items marked `pub` that aren't reachable from other crates.
1275    UnreachablePub => [UNREACHABLE_PUB]
1276);
1277
1278impl UnreachablePub {
1279    fn perform_lint(
1280        &self,
1281        cx: &LateContext<'_>,
1282        what: &str,
1283        def_id: LocalDefId,
1284        vis_span: Span,
1285        exportable: bool,
1286    ) {
1287        let mut applicability = Applicability::MachineApplicable;
1288        if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
1289        {
1290            // prefer suggesting `pub(super)` instead of `pub(crate)` when possible,
1291            // except when `pub(super) == pub(crate)`
1292            let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) =
1293                cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| {
1294                    effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable)
1295                })
1296                && let parent_parent = cx
1297                    .tcx
1298                    .parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into())
1299                && *restricted_did == parent_parent.to_local_def_id()
1300                && !restricted_did.to_def_id().is_crate_root()
1301            {
1302                "pub(super)"
1303            } else {
1304                "pub(crate)"
1305            };
1306
1307            if vis_span.from_expansion() {
1308                applicability = Applicability::MaybeIncorrect;
1309            }
1310            let def_span = cx.tcx.def_span(def_id);
1311            cx.emit_span_lint(
1312                UNREACHABLE_PUB,
1313                def_span,
1314                BuiltinUnreachablePub {
1315                    what,
1316                    new_vis,
1317                    suggestion: (vis_span, applicability),
1318                    help: exportable,
1319                },
1320            );
1321        }
1322    }
1323}
1324
1325impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1326    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1327        // Do not warn for fake `use` statements.
1328        if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1329            return;
1330        }
1331        self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
1332    }
1333
1334    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
1335        self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
1336    }
1337
1338    fn check_field_def(&mut self, _cx: &LateContext<'_>, _field: &hir::FieldDef<'_>) {
1339        // - If an ADT definition is reported then we don't need to check fields
1340        //   (as it would add unnecessary complexity to the source code, the struct
1341        //   definition is in the immediate proximity to give the "real" visibility).
1342        // - If an ADT is not reported because it's not `pub` - we don't need to
1343        //   check fields.
1344        // - If an ADT is not reported because it's reachable - we also don't need
1345        //   to check fields because then they are reachable by construction if they
1346        //   are pub.
1347        //
1348        // Therefore in no case we check the fields.
1349        //
1350        // cf. https://github.com/rust-lang/rust/pull/126013#issuecomment-2152839205
1351        // cf. https://github.com/rust-lang/rust/pull/126040#issuecomment-2152944506
1352    }
1353
1354    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
1355        // Only lint inherent impl items.
1356        if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
1357            self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
1358        }
1359    }
1360}
1361
1362declare_lint! {
1363    /// The `type_alias_bounds` lint detects bounds in type aliases.
1364    ///
1365    /// ### Example
1366    ///
1367    /// ```rust
1368    /// type SendVec<T: Send> = Vec<T>;
1369    /// ```
1370    ///
1371    /// {{produces}}
1372    ///
1373    /// ### Explanation
1374    ///
1375    /// Trait and lifetime bounds on generic parameters and in where clauses of
1376    /// type aliases are not checked at usage sites of the type alias. Moreover,
1377    /// they are not thoroughly checked for correctness at their definition site
1378    /// either similar to the aliased type.
1379    ///
1380    /// This is a known limitation of the type checker that may be lifted in a
1381    /// future edition. Permitting such bounds in light of this was unintentional.
1382    ///
1383    /// While these bounds may have secondary effects such as enabling the use of
1384    /// "shorthand" associated type paths[^1] and affecting the default trait
1385    /// object lifetime[^2] of trait object types passed to the type alias, this
1386    /// should not have been allowed until the aforementioned restrictions of the
1387    /// type checker have been lifted.
1388    ///
1389    /// Using such bounds is highly discouraged as they are actively misleading.
1390    ///
1391    /// [^1]: I.e., paths of the form `T::Assoc` where `T` is a type parameter
1392    /// bounded by trait `Trait` which defines an associated type called `Assoc`
1393    /// as opposed to a fully qualified path of the form `<T as Trait>::Assoc`.
1394    /// [^2]: <https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes>
1395    TYPE_ALIAS_BOUNDS,
1396    Warn,
1397    "bounds in type aliases are not enforced"
1398}
1399
1400declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]);
1401
1402impl TypeAliasBounds {
1403    pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool {
1404        // Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults.
1405        if let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind
1406            && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_)))
1407            && pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS
1408            && pred.bounded_ty.as_generic_param().is_some()
1409        {
1410            return true;
1411        }
1412        false
1413    }
1414}
1415
1416impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1417    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1418        let hir::ItemKind::TyAlias(_, hir_ty, generics) = item.kind else { return };
1419
1420        // There must not be a where clause.
1421        if generics.predicates.is_empty() {
1422            return;
1423        }
1424
1425        // Bounds of lazy type aliases and TAITs are respected.
1426        if cx.tcx.type_alias_is_lazy(item.owner_id) {
1427            return;
1428        }
1429
1430        // FIXME(generic_const_exprs): Revisit this before stabilization.
1431        // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`.
1432        let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
1433        if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
1434            && cx.tcx.features().generic_const_exprs()
1435        {
1436            return;
1437        }
1438
1439        // NOTE(inherent_associated_types): While we currently do take some bounds in type
1440        // aliases into consideration during IAT *selection*, we don't perform full use+def
1441        // site wfchecking for such type aliases. Therefore TAB should still trigger.
1442        // See also `tests/ui/associated-inherent-types/type-alias-bounds.rs`.
1443
1444        let mut where_spans = Vec::new();
1445        let mut inline_spans = Vec::new();
1446        let mut inline_sugg = Vec::new();
1447
1448        for p in generics.predicates {
1449            let span = p.span;
1450            if p.kind.in_where_clause() {
1451                where_spans.push(span);
1452            } else {
1453                for b in p.kind.bounds() {
1454                    inline_spans.push(b.span());
1455                }
1456                inline_sugg.push((span, String::new()));
1457            }
1458        }
1459
1460        let mut ty = Some(hir_ty);
1461        let enable_feat_help = cx.tcx.sess.is_nightly_build();
1462
1463        if let [.., label_sp] = *where_spans {
1464            cx.emit_span_lint(
1465                TYPE_ALIAS_BOUNDS,
1466                where_spans,
1467                BuiltinTypeAliasBounds {
1468                    in_where_clause: true,
1469                    label: label_sp,
1470                    enable_feat_help,
1471                    suggestions: vec![(generics.where_clause_span, String::new())],
1472                    preds: generics.predicates,
1473                    ty: ty.take(),
1474                },
1475            );
1476        }
1477        if let [.., label_sp] = *inline_spans {
1478            cx.emit_span_lint(
1479                TYPE_ALIAS_BOUNDS,
1480                inline_spans,
1481                BuiltinTypeAliasBounds {
1482                    in_where_clause: false,
1483                    label: label_sp,
1484                    enable_feat_help,
1485                    suggestions: inline_sugg,
1486                    preds: generics.predicates,
1487                    ty,
1488                },
1489            );
1490        }
1491    }
1492}
1493
1494pub(crate) struct ShorthandAssocTyCollector {
1495    pub(crate) qselves: Vec<Span>,
1496}
1497
1498impl hir::intravisit::Visitor<'_> for ShorthandAssocTyCollector {
1499    fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) {
1500        // Look for "type-parameter shorthand-associated-types". I.e., paths of the
1501        // form `T::Assoc` with `T` type param. These are reliant on trait bounds.
1502        if let hir::QPath::TypeRelative(qself, _) = qpath
1503            && qself.as_generic_param().is_some()
1504        {
1505            self.qselves.push(qself.span);
1506        }
1507        hir::intravisit::walk_qpath(self, qpath, id)
1508    }
1509}
1510
1511declare_lint! {
1512    /// The `trivial_bounds` lint detects trait bounds that don't depend on
1513    /// any type parameters.
1514    ///
1515    /// ### Example
1516    ///
1517    /// ```rust
1518    /// #![feature(trivial_bounds)]
1519    /// pub struct A where i32: Copy;
1520    /// ```
1521    ///
1522    /// {{produces}}
1523    ///
1524    /// ### Explanation
1525    ///
1526    /// Usually you would not write a trait bound that you know is always
1527    /// true, or never true. However, when using macros, the macro may not
1528    /// know whether or not the constraint would hold or not at the time when
1529    /// generating the code. Currently, the compiler does not alert you if the
1530    /// constraint is always true, and generates an error if it is never true.
1531    /// The `trivial_bounds` feature changes this to be a warning in both
1532    /// cases, giving macros more freedom and flexibility to generate code,
1533    /// while still providing a signal when writing non-macro code that
1534    /// something is amiss.
1535    ///
1536    /// See [RFC 2056] for more details. This feature is currently only
1537    /// available on the nightly channel, see [tracking issue #48214].
1538    ///
1539    /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1540    /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1541    TRIVIAL_BOUNDS,
1542    Warn,
1543    "these bounds don't depend on an type parameters"
1544}
1545
1546declare_lint_pass!(
1547    /// Lint for trait and lifetime bounds that don't depend on type parameters
1548    /// which either do nothing, or stop the item from being used.
1549    TrivialConstraints => [TRIVIAL_BOUNDS]
1550);
1551
1552impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1553    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1554        use rustc_middle::ty::ClauseKind;
1555
1556        if cx.tcx.features().trivial_bounds() {
1557            let predicates = cx.tcx.predicates_of(item.owner_id);
1558            for &(predicate, span) in predicates.predicates {
1559                let predicate_kind_name = match predicate.kind().skip_binder() {
1560                    ClauseKind::Trait(..) => "trait",
1561                    ClauseKind::TypeOutlives(..) |
1562                    ClauseKind::RegionOutlives(..) => "lifetime",
1563
1564                    // `ConstArgHasType` is never global as `ct` is always a param
1565                    ClauseKind::ConstArgHasType(..)
1566                    // Ignore projections, as they can only be global
1567                    // if the trait bound is global
1568                    | ClauseKind::Projection(..)
1569                    // Ignore bounds that a user can't type
1570                    | ClauseKind::WellFormed(..)
1571                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
1572                    | ClauseKind::ConstEvaluatable(..)
1573                    // Users don't write this directly, only via another trait ref.
1574                    | ty::ClauseKind::HostEffect(..) => continue,
1575                };
1576                if predicate.is_global() {
1577                    cx.emit_span_lint(
1578                        TRIVIAL_BOUNDS,
1579                        span,
1580                        BuiltinTrivialBounds { predicate_kind_name, predicate },
1581                    );
1582                }
1583            }
1584        }
1585    }
1586}
1587
1588declare_lint! {
1589    /// The `double_negations` lint detects expressions of the form `--x`.
1590    ///
1591    /// ### Example
1592    ///
1593    /// ```rust
1594    /// fn main() {
1595    ///     let x = 1;
1596    ///     let _b = --x;
1597    /// }
1598    /// ```
1599    ///
1600    /// {{produces}}
1601    ///
1602    /// ### Explanation
1603    ///
1604    /// Negating something twice is usually the same as not negating it at all.
1605    /// However, a double negation in Rust can easily be confused with the
1606    /// prefix decrement operator that exists in many languages derived from C.
1607    /// Use `-(-x)` if you really wanted to negate the value twice.
1608    ///
1609    /// To decrement a value, use `x -= 1` instead.
1610    pub DOUBLE_NEGATIONS,
1611    Warn,
1612    "detects expressions of the form `--x`"
1613}
1614
1615declare_lint_pass!(
1616    /// Lint for expressions of the form `--x` that can be confused with C's
1617    /// prefix decrement operator.
1618    DoubleNegations => [DOUBLE_NEGATIONS]
1619);
1620
1621impl EarlyLintPass for DoubleNegations {
1622    #[inline]
1623    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1624        // only lint on the innermost `--` in a chain of `-` operators,
1625        // even if there are 3 or more negations
1626        if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
1627            && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
1628            && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
1629        {
1630            cx.emit_span_lint(
1631                DOUBLE_NEGATIONS,
1632                expr.span,
1633                BuiltinDoubleNegations {
1634                    add_parens: BuiltinDoubleNegationsAddParens {
1635                        start_span: inner.span.shrink_to_lo(),
1636                        end_span: inner.span.shrink_to_hi(),
1637                    },
1638                },
1639            );
1640        }
1641    }
1642}
1643
1644declare_lint_pass!(
1645    /// Does nothing as a lint pass, but registers some `Lint`s
1646    /// which are used by other parts of the compiler.
1647    SoftLints => [
1648        WHILE_TRUE,
1649        NON_SHORTHAND_FIELD_PATTERNS,
1650        UNSAFE_CODE,
1651        MISSING_DOCS,
1652        MISSING_COPY_IMPLEMENTATIONS,
1653        MISSING_DEBUG_IMPLEMENTATIONS,
1654        ANONYMOUS_PARAMETERS,
1655        UNUSED_DOC_COMMENTS,
1656        NO_MANGLE_CONST_ITEMS,
1657        NO_MANGLE_GENERIC_ITEMS,
1658        MUTABLE_TRANSMUTES,
1659        UNSTABLE_FEATURES,
1660        UNREACHABLE_PUB,
1661        TYPE_ALIAS_BOUNDS,
1662        TRIVIAL_BOUNDS,
1663        DOUBLE_NEGATIONS
1664    ]
1665);
1666
1667declare_lint! {
1668    /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1669    /// pattern], which is deprecated.
1670    ///
1671    /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1672    ///
1673    /// ### Example
1674    ///
1675    /// ```rust,edition2018
1676    /// let x = 123;
1677    /// match x {
1678    ///     0...100 => {}
1679    ///     _ => {}
1680    /// }
1681    /// ```
1682    ///
1683    /// {{produces}}
1684    ///
1685    /// ### Explanation
1686    ///
1687    /// The `...` range pattern syntax was changed to `..=` to avoid potential
1688    /// confusion with the [`..` range expression]. Use the new form instead.
1689    ///
1690    /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1691    pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1692    Warn,
1693    "`...` range patterns are deprecated",
1694    @future_incompatible = FutureIncompatibleInfo {
1695        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
1696        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1697    };
1698}
1699
1700#[derive(Default)]
1701pub struct EllipsisInclusiveRangePatterns {
1702    /// If `Some(_)`, suppress all subsequent pattern
1703    /// warnings for better diagnostics.
1704    node_id: Option<ast::NodeId>,
1705}
1706
1707impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1708
1709impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1710    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1711        if self.node_id.is_some() {
1712            // Don't recursively warn about patterns inside range endpoints.
1713            return;
1714        }
1715
1716        use self::ast::PatKind;
1717        use self::ast::RangeSyntax::DotDotDot;
1718
1719        /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1720        /// corresponding to the ellipsis.
1721        fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1722            match &pat.kind {
1723                PatKind::Range(
1724                    a,
1725                    Some(b),
1726                    Spanned { span, node: RangeEnd::Included(DotDotDot) },
1727                ) => Some((a.as_deref(), b, *span)),
1728                _ => None,
1729            }
1730        }
1731
1732        let (parentheses, endpoints) = match &pat.kind {
1733            PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
1734            _ => (false, matches_ellipsis_pat(pat)),
1735        };
1736
1737        if let Some((start, end, join)) = endpoints {
1738            if parentheses {
1739                self.node_id = Some(pat.id);
1740                let end = expr_to_string(end);
1741                let replace = match start {
1742                    Some(start) => format!("&({}..={})", expr_to_string(start), end),
1743                    None => format!("&(..={end})"),
1744                };
1745                if join.edition() >= Edition::Edition2021 {
1746                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
1747                        span: pat.span,
1748                        suggestion: pat.span,
1749                        replace,
1750                    });
1751                } else {
1752                    cx.emit_span_lint(
1753                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1754                        pat.span,
1755                        BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {
1756                            suggestion: pat.span,
1757                            replace,
1758                        },
1759                    );
1760                }
1761            } else {
1762                let replace = "..=";
1763                if join.edition() >= Edition::Edition2021 {
1764                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
1765                        span: pat.span,
1766                        suggestion: join,
1767                        replace: replace.to_string(),
1768                    });
1769                } else {
1770                    cx.emit_span_lint(
1771                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1772                        join,
1773                        BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {
1774                            suggestion: join,
1775                        },
1776                    );
1777                }
1778            };
1779        }
1780    }
1781
1782    fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1783        if let Some(node_id) = self.node_id {
1784            if pat.id == node_id {
1785                self.node_id = None
1786            }
1787        }
1788    }
1789}
1790
1791declare_lint! {
1792    /// The `keyword_idents_2018` lint detects edition keywords being used as an
1793    /// identifier.
1794    ///
1795    /// ### Example
1796    ///
1797    /// ```rust,edition2015,compile_fail
1798    /// #![deny(keyword_idents_2018)]
1799    /// // edition 2015
1800    /// fn dyn() {}
1801    /// ```
1802    ///
1803    /// {{produces}}
1804    ///
1805    /// ### Explanation
1806    ///
1807    /// Rust [editions] allow the language to evolve without breaking
1808    /// backwards compatibility. This lint catches code that uses new keywords
1809    /// that are added to the language that are used as identifiers (such as a
1810    /// variable name, function name, etc.). If you switch the compiler to a
1811    /// new edition without updating the code, then it will fail to compile if
1812    /// you are using a new keyword as an identifier.
1813    ///
1814    /// You can manually change the identifiers to a non-keyword, or use a
1815    /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1816    ///
1817    /// This lint solves the problem automatically. It is "allow" by default
1818    /// because the code is perfectly valid in older editions. The [`cargo
1819    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1820    /// and automatically apply the suggested fix from the compiler (which is
1821    /// to use a raw identifier). This provides a completely automated way to
1822    /// update old code for a new edition.
1823    ///
1824    /// [editions]: https://doc.rust-lang.org/edition-guide/
1825    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1826    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1827    pub KEYWORD_IDENTS_2018,
1828    Allow,
1829    "detects edition keywords being used as an identifier",
1830    @future_incompatible = FutureIncompatibleInfo {
1831        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
1832        reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1833    };
1834}
1835
1836declare_lint! {
1837    /// The `keyword_idents_2024` lint detects edition keywords being used as an
1838    /// identifier.
1839    ///
1840    /// ### Example
1841    ///
1842    /// ```rust,edition2015,compile_fail
1843    /// #![deny(keyword_idents_2024)]
1844    /// // edition 2015
1845    /// fn gen() {}
1846    /// ```
1847    ///
1848    /// {{produces}}
1849    ///
1850    /// ### Explanation
1851    ///
1852    /// Rust [editions] allow the language to evolve without breaking
1853    /// backwards compatibility. This lint catches code that uses new keywords
1854    /// that are added to the language that are used as identifiers (such as a
1855    /// variable name, function name, etc.). If you switch the compiler to a
1856    /// new edition without updating the code, then it will fail to compile if
1857    /// you are using a new keyword as an identifier.
1858    ///
1859    /// You can manually change the identifiers to a non-keyword, or use a
1860    /// [raw identifier], for example `r#gen`, to transition to a new edition.
1861    ///
1862    /// This lint solves the problem automatically. It is "allow" by default
1863    /// because the code is perfectly valid in older editions. The [`cargo
1864    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1865    /// and automatically apply the suggested fix from the compiler (which is
1866    /// to use a raw identifier). This provides a completely automated way to
1867    /// update old code for a new edition.
1868    ///
1869    /// [editions]: https://doc.rust-lang.org/edition-guide/
1870    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1871    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1872    pub KEYWORD_IDENTS_2024,
1873    Allow,
1874    "detects edition keywords being used as an identifier",
1875    @future_incompatible = FutureIncompatibleInfo {
1876        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
1877        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>",
1878    };
1879}
1880
1881declare_lint_pass!(
1882    /// Check for uses of edition keywords used as an identifier.
1883    KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
1884);
1885
1886struct UnderMacro(bool);
1887
1888impl KeywordIdents {
1889    fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
1890        // Check if the preceding token is `$`, because we want to allow `$async`, etc.
1891        let mut prev_dollar = false;
1892        for tt in tokens.iter() {
1893            match tt {
1894                // Only report non-raw idents.
1895                TokenTree::Token(token, _) => {
1896                    if let Some((ident, token::IdentIsRaw::No)) = token.ident() {
1897                        if !prev_dollar {
1898                            self.check_ident_token(cx, UnderMacro(true), ident, "");
1899                        }
1900                    } else if let Some((ident, token::IdentIsRaw::No)) = token.lifetime() {
1901                        self.check_ident_token(
1902                            cx,
1903                            UnderMacro(true),
1904                            ident.without_first_quote(),
1905                            "'",
1906                        );
1907                    } else if token.kind == TokenKind::Dollar {
1908                        prev_dollar = true;
1909                        continue;
1910                    }
1911                }
1912                TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
1913            }
1914            prev_dollar = false;
1915        }
1916    }
1917
1918    fn check_ident_token(
1919        &mut self,
1920        cx: &EarlyContext<'_>,
1921        UnderMacro(under_macro): UnderMacro,
1922        ident: Ident,
1923        prefix: &'static str,
1924    ) {
1925        let (lint, edition) = match ident.name {
1926            kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1927
1928            // rust-lang/rust#56327: Conservatively do not
1929            // attempt to report occurrences of `dyn` within
1930            // macro definitions or invocations, because `dyn`
1931            // can legitimately occur as a contextual keyword
1932            // in 2015 code denoting its 2018 meaning, and we
1933            // do not want rustfix to inject bugs into working
1934            // code by rewriting such occurrences.
1935            //
1936            // But if we see `dyn` outside of a macro, we know
1937            // its precise role in the parsed AST and thus are
1938            // assured this is truly an attempt to use it as
1939            // an identifier.
1940            kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1941
1942            kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
1943
1944            _ => return,
1945        };
1946
1947        // Don't lint `r#foo`.
1948        if ident.span.edition() >= edition
1949            || cx.sess().psess.raw_identifier_spans.contains(ident.span)
1950        {
1951            return;
1952        }
1953
1954        cx.emit_span_lint(
1955            lint,
1956            ident.span,
1957            BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix },
1958        );
1959    }
1960}
1961
1962impl EarlyLintPass for KeywordIdents {
1963    fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
1964        self.check_tokens(cx, &mac_def.body.tokens);
1965    }
1966    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
1967        self.check_tokens(cx, &mac.args.tokens);
1968    }
1969    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) {
1970        if ident.name.as_str().starts_with('\'') {
1971            self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'");
1972        } else {
1973            self.check_ident_token(cx, UnderMacro(false), *ident, "");
1974        }
1975    }
1976}
1977
1978declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
1979
1980impl ExplicitOutlivesRequirements {
1981    fn lifetimes_outliving_lifetime<'tcx>(
1982        tcx: TyCtxt<'tcx>,
1983        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
1984        item: LocalDefId,
1985        lifetime: LocalDefId,
1986    ) -> Vec<ty::Region<'tcx>> {
1987        let item_generics = tcx.generics_of(item);
1988
1989        inferred_outlives
1990            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
1991                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a.kind() {
1992                    ty::ReEarlyParam(ebr)
1993                        if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() =>
1994                    {
1995                        Some(b)
1996                    }
1997                    _ => None,
1998                },
1999                _ => None,
2000            })
2001            .collect()
2002    }
2003
2004    fn lifetimes_outliving_type<'tcx>(
2005        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
2006        index: u32,
2007    ) -> Vec<ty::Region<'tcx>> {
2008        inferred_outlives
2009            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
2010                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
2011                    a.is_param(index).then_some(b)
2012                }
2013                _ => None,
2014            })
2015            .collect()
2016    }
2017
2018    fn collect_outlives_bound_spans<'tcx>(
2019        &self,
2020        tcx: TyCtxt<'tcx>,
2021        bounds: &hir::GenericBounds<'_>,
2022        inferred_outlives: &[ty::Region<'tcx>],
2023        predicate_span: Span,
2024        item: DefId,
2025    ) -> Vec<(usize, Span)> {
2026        use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
2027
2028        let item_generics = tcx.generics_of(item);
2029
2030        bounds
2031            .iter()
2032            .enumerate()
2033            .filter_map(|(i, bound)| {
2034                let hir::GenericBound::Outlives(lifetime) = bound else {
2035                    return None;
2036                };
2037
2038                let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
2039                    Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
2040                        .iter()
2041                        .any(|r| matches!(r.kind(), ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })),
2042                    _ => false,
2043                };
2044
2045                if !is_inferred {
2046                    return None;
2047                }
2048
2049                let span = bound.span().find_ancestor_inside(predicate_span)?;
2050                if span.in_external_macro(tcx.sess.source_map()) {
2051                    return None;
2052                }
2053
2054                Some((i, span))
2055            })
2056            .collect()
2057    }
2058
2059    fn consolidate_outlives_bound_spans(
2060        &self,
2061        lo: Span,
2062        bounds: &hir::GenericBounds<'_>,
2063        bound_spans: Vec<(usize, Span)>,
2064    ) -> Vec<Span> {
2065        if bounds.is_empty() {
2066            return Vec::new();
2067        }
2068        if bound_spans.len() == bounds.len() {
2069            let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
2070            // If all bounds are inferable, we want to delete the colon, so
2071            // start from just after the parameter (span passed as argument)
2072            vec![lo.to(last_bound_span)]
2073        } else {
2074            let mut merged = Vec::new();
2075            let mut last_merged_i = None;
2076
2077            let mut from_start = true;
2078            for (i, bound_span) in bound_spans {
2079                match last_merged_i {
2080                    // If the first bound is inferable, our span should also eat the leading `+`.
2081                    None if i == 0 => {
2082                        merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2083                        last_merged_i = Some(0);
2084                    }
2085                    // If consecutive bounds are inferable, merge their spans
2086                    Some(h) if i == h + 1 => {
2087                        if let Some(tail) = merged.last_mut() {
2088                            // Also eat the trailing `+` if the first
2089                            // more-than-one bound is inferable
2090                            let to_span = if from_start && i < bounds.len() {
2091                                bounds[i + 1].span().shrink_to_lo()
2092                            } else {
2093                                bound_span
2094                            };
2095                            *tail = tail.to(to_span);
2096                            last_merged_i = Some(i);
2097                        } else {
2098                            bug!("another bound-span visited earlier");
2099                        }
2100                    }
2101                    _ => {
2102                        // When we find a non-inferable bound, subsequent inferable bounds
2103                        // won't be consecutive from the start (and we'll eat the leading
2104                        // `+` rather than the trailing one)
2105                        from_start = false;
2106                        merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
2107                        last_merged_i = Some(i);
2108                    }
2109                }
2110            }
2111            merged
2112        }
2113    }
2114}
2115
2116impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2117    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
2118        use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
2119
2120        let def_id = item.owner_id.def_id;
2121        if let hir::ItemKind::Struct(_, _, hir_generics)
2122        | hir::ItemKind::Enum(_, _, hir_generics)
2123        | hir::ItemKind::Union(_, _, hir_generics) = item.kind
2124        {
2125            let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2126            if inferred_outlives.is_empty() {
2127                return;
2128            }
2129
2130            let ty_generics = cx.tcx.generics_of(def_id);
2131            let num_where_predicates = hir_generics
2132                .predicates
2133                .iter()
2134                .filter(|predicate| predicate.kind.in_where_clause())
2135                .count();
2136
2137            let mut bound_count = 0;
2138            let mut lint_spans = Vec::new();
2139            let mut where_lint_spans = Vec::new();
2140            let mut dropped_where_predicate_count = 0;
2141            for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
2142                let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
2143                    match where_predicate.kind {
2144                        hir::WherePredicateKind::RegionPredicate(predicate) => {
2145                            if let Some(ResolvedArg::EarlyBound(region_def_id)) =
2146                                cx.tcx.named_bound_var(predicate.lifetime.hir_id)
2147                            {
2148                                (
2149                                    Self::lifetimes_outliving_lifetime(
2150                                        cx.tcx,
2151                                        // don't warn if the inferred span actually came from the predicate we're looking at
2152                                        // this happens if the type is recursively defined
2153                                        inferred_outlives.iter().filter(|(_, span)| {
2154                                            !where_predicate.span.contains(*span)
2155                                        }),
2156                                        item.owner_id.def_id,
2157                                        region_def_id,
2158                                    ),
2159                                    &predicate.bounds,
2160                                    where_predicate.span,
2161                                    predicate.in_where_clause,
2162                                )
2163                            } else {
2164                                continue;
2165                            }
2166                        }
2167                        hir::WherePredicateKind::BoundPredicate(predicate) => {
2168                            // FIXME we can also infer bounds on associated types,
2169                            // and should check for them here.
2170                            match predicate.bounded_ty.kind {
2171                                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
2172                                    let Res::Def(DefKind::TyParam, def_id) = path.res else {
2173                                        continue;
2174                                    };
2175                                    let index = ty_generics.param_def_id_to_index[&def_id];
2176                                    (
2177                                        Self::lifetimes_outliving_type(
2178                                            // don't warn if the inferred span actually came from the predicate we're looking at
2179                                            // this happens if the type is recursively defined
2180                                            inferred_outlives.iter().filter(|(_, span)| {
2181                                                !where_predicate.span.contains(*span)
2182                                            }),
2183                                            index,
2184                                        ),
2185                                        &predicate.bounds,
2186                                        where_predicate.span,
2187                                        predicate.origin == PredicateOrigin::WhereClause,
2188                                    )
2189                                }
2190                                _ => {
2191                                    continue;
2192                                }
2193                            }
2194                        }
2195                        _ => continue,
2196                    };
2197                if relevant_lifetimes.is_empty() {
2198                    continue;
2199                }
2200
2201                let bound_spans = self.collect_outlives_bound_spans(
2202                    cx.tcx,
2203                    bounds,
2204                    &relevant_lifetimes,
2205                    predicate_span,
2206                    item.owner_id.to_def_id(),
2207                );
2208                bound_count += bound_spans.len();
2209
2210                let drop_predicate = bound_spans.len() == bounds.len();
2211                if drop_predicate && in_where_clause {
2212                    dropped_where_predicate_count += 1;
2213                }
2214
2215                if drop_predicate {
2216                    if !in_where_clause {
2217                        lint_spans.push(predicate_span);
2218                    } else if predicate_span.from_expansion() {
2219                        // Don't try to extend the span if it comes from a macro expansion.
2220                        where_lint_spans.push(predicate_span);
2221                    } else if i + 1 < num_where_predicates {
2222                        // If all the bounds on a predicate were inferable and there are
2223                        // further predicates, we want to eat the trailing comma.
2224                        let next_predicate_span = hir_generics.predicates[i + 1].span;
2225                        if next_predicate_span.from_expansion() {
2226                            where_lint_spans.push(predicate_span);
2227                        } else {
2228                            where_lint_spans
2229                                .push(predicate_span.to(next_predicate_span.shrink_to_lo()));
2230                        }
2231                    } else {
2232                        // Eat the optional trailing comma after the last predicate.
2233                        let where_span = hir_generics.where_clause_span;
2234                        if where_span.from_expansion() {
2235                            where_lint_spans.push(predicate_span);
2236                        } else {
2237                            where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi()));
2238                        }
2239                    }
2240                } else {
2241                    where_lint_spans.extend(self.consolidate_outlives_bound_spans(
2242                        predicate_span.shrink_to_lo(),
2243                        bounds,
2244                        bound_spans,
2245                    ));
2246                }
2247            }
2248
2249            // If all predicates in where clause are inferable, drop the entire clause
2250            // (including the `where`)
2251            if hir_generics.has_where_clause_predicates
2252                && dropped_where_predicate_count == num_where_predicates
2253            {
2254                let where_span = hir_generics.where_clause_span;
2255                // Extend the where clause back to the closing `>` of the
2256                // generics, except for tuple struct, which have the `where`
2257                // after the fields of the struct.
2258                let full_where_span =
2259                    if let hir::ItemKind::Struct(_, hir::VariantData::Tuple(..), _) = item.kind {
2260                        where_span
2261                    } else {
2262                        hir_generics.span.shrink_to_hi().to(where_span)
2263                    };
2264
2265                // Due to macro expansions, the `full_where_span` might not actually contain all
2266                // predicates.
2267                if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
2268                    lint_spans.push(full_where_span);
2269                } else {
2270                    lint_spans.extend(where_lint_spans);
2271                }
2272            } else {
2273                lint_spans.extend(where_lint_spans);
2274            }
2275
2276            if !lint_spans.is_empty() {
2277                // Do not automatically delete outlives requirements from macros.
2278                let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
2279                {
2280                    Applicability::MachineApplicable
2281                } else {
2282                    Applicability::MaybeIncorrect
2283                };
2284
2285                // Due to macros, there might be several predicates with the same span
2286                // and we only want to suggest removing them once.
2287                lint_spans.sort_unstable();
2288                lint_spans.dedup();
2289
2290                cx.emit_span_lint(
2291                    EXPLICIT_OUTLIVES_REQUIREMENTS,
2292                    lint_spans.clone(),
2293                    BuiltinExplicitOutlives {
2294                        count: bound_count,
2295                        suggestion: BuiltinExplicitOutlivesSuggestion {
2296                            spans: lint_spans,
2297                            applicability,
2298                        },
2299                    },
2300                );
2301            }
2302        }
2303    }
2304}
2305
2306declare_lint! {
2307    /// The `incomplete_features` lint detects unstable features enabled with
2308    /// the [`feature` attribute] that may function improperly in some or all
2309    /// cases.
2310    ///
2311    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2312    ///
2313    /// ### Example
2314    ///
2315    /// ```rust
2316    /// #![feature(generic_const_exprs)]
2317    /// ```
2318    ///
2319    /// {{produces}}
2320    ///
2321    /// ### Explanation
2322    ///
2323    /// Although it is encouraged for people to experiment with unstable
2324    /// features, some of them are known to be incomplete or faulty. This lint
2325    /// is a signal that the feature has not yet been finished, and you may
2326    /// experience problems with it.
2327    pub INCOMPLETE_FEATURES,
2328    Warn,
2329    "incomplete features that may function improperly in some or all cases"
2330}
2331
2332declare_lint! {
2333    /// The `internal_features` lint detects unstable features enabled with
2334    /// the [`feature` attribute] that are internal to the compiler or standard
2335    /// library.
2336    ///
2337    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2338    ///
2339    /// ### Example
2340    ///
2341    /// ```rust
2342    /// #![feature(rustc_attrs)]
2343    /// ```
2344    ///
2345    /// {{produces}}
2346    ///
2347    /// ### Explanation
2348    ///
2349    /// These features are an implementation detail of the compiler and standard
2350    /// library and are not supposed to be used in user code.
2351    pub INTERNAL_FEATURES,
2352    Warn,
2353    "internal features are not supposed to be used"
2354}
2355
2356declare_lint_pass!(
2357    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
2358    IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
2359);
2360
2361impl EarlyLintPass for IncompleteInternalFeatures {
2362    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
2363        let features = cx.builder.features();
2364        let lang_features =
2365            features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
2366        let lib_features =
2367            features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
2368
2369        lang_features
2370            .chain(lib_features)
2371            .filter(|(name, _)| features.incomplete(*name) || features.internal(*name))
2372            .for_each(|(name, span)| {
2373                if features.incomplete(name) {
2374                    let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
2375                        .map(|n| BuiltinFeatureIssueNote { n });
2376                    let help =
2377                        HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
2378
2379                    cx.emit_span_lint(
2380                        INCOMPLETE_FEATURES,
2381                        span,
2382                        BuiltinIncompleteFeatures { name, note, help },
2383                    );
2384                } else {
2385                    cx.emit_span_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name });
2386                }
2387            });
2388    }
2389}
2390
2391const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
2392
2393declare_lint! {
2394    /// The `invalid_value` lint detects creating a value that is not valid,
2395    /// such as a null reference.
2396    ///
2397    /// ### Example
2398    ///
2399    /// ```rust,no_run
2400    /// # #![allow(unused)]
2401    /// unsafe {
2402    ///     let x: &'static i32 = std::mem::zeroed();
2403    /// }
2404    /// ```
2405    ///
2406    /// {{produces}}
2407    ///
2408    /// ### Explanation
2409    ///
2410    /// In some situations the compiler can detect that the code is creating
2411    /// an invalid value, which should be avoided.
2412    ///
2413    /// In particular, this lint will check for improper use of
2414    /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2415    /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2416    /// lint should provide extra information to indicate what the problem is
2417    /// and a possible solution.
2418    ///
2419    /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2420    /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2421    /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2422    /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2423    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2424    pub INVALID_VALUE,
2425    Warn,
2426    "an invalid value is being created (such as a null reference)"
2427}
2428
2429declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2430
2431/// Information about why a type cannot be initialized this way.
2432pub struct InitError {
2433    pub(crate) message: String,
2434    /// Spans from struct fields and similar that can be obtained from just the type.
2435    pub(crate) span: Option<Span>,
2436    /// Used to report a trace through adts.
2437    pub(crate) nested: Option<Box<InitError>>,
2438}
2439impl InitError {
2440    fn spanned(self, span: Span) -> InitError {
2441        Self { span: Some(span), ..self }
2442    }
2443
2444    fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
2445        assert!(self.nested.is_none());
2446        Self { nested: nested.into().map(Box::new), ..self }
2447    }
2448}
2449
2450impl<'a> From<&'a str> for InitError {
2451    fn from(s: &'a str) -> Self {
2452        s.to_owned().into()
2453    }
2454}
2455impl From<String> for InitError {
2456    fn from(message: String) -> Self {
2457        Self { message, span: None, nested: None }
2458    }
2459}
2460
2461impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2462    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2463        #[derive(Debug, Copy, Clone, PartialEq)]
2464        enum InitKind {
2465            Zeroed,
2466            Uninit,
2467        }
2468
2469        /// Test if this constant is all-0.
2470        fn is_zero(expr: &hir::Expr<'_>) -> bool {
2471            use hir::ExprKind::*;
2472            use rustc_ast::LitKind::*;
2473            match &expr.kind {
2474                Lit(lit) => {
2475                    if let Int(i, _) = lit.node {
2476                        i == 0
2477                    } else {
2478                        false
2479                    }
2480                }
2481                Tup(tup) => tup.iter().all(is_zero),
2482                _ => false,
2483            }
2484        }
2485
2486        /// Determine if this expression is a "dangerous initialization".
2487        fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
2488            if let hir::ExprKind::Call(path_expr, args) = expr.kind {
2489                // Find calls to `mem::{uninitialized,zeroed}` methods.
2490                if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2491                    let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2492                    match cx.tcx.get_diagnostic_name(def_id) {
2493                        Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2494                        Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2495                        Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2496                        _ => {}
2497                    }
2498                }
2499            } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
2500                // Find problematic calls to `MaybeUninit::assume_init`.
2501                let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
2502                if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2503                    // This is a call to *some* method named `assume_init`.
2504                    // See if the `self` parameter is one of the dangerous constructors.
2505                    if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
2506                        if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2507                            let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2508                            match cx.tcx.get_diagnostic_name(def_id) {
2509                                Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2510                                Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2511                                _ => {}
2512                            }
2513                        }
2514                    }
2515                }
2516            }
2517
2518            None
2519        }
2520
2521        fn variant_find_init_error<'tcx>(
2522            cx: &LateContext<'tcx>,
2523            ty: Ty<'tcx>,
2524            variant: &VariantDef,
2525            args: ty::GenericArgsRef<'tcx>,
2526            descr: &str,
2527            init: InitKind,
2528        ) -> Option<InitError> {
2529            let mut field_err = variant.fields.iter().find_map(|field| {
2530                ty_find_init_error(cx, field.ty(cx.tcx, args), init).map(|mut err| {
2531                    if !field.did.is_local() {
2532                        err
2533                    } else if err.span.is_none() {
2534                        err.span = Some(cx.tcx.def_span(field.did));
2535                        write!(&mut err.message, " (in this {descr})").unwrap();
2536                        err
2537                    } else {
2538                        InitError::from(format!("in this {descr}"))
2539                            .spanned(cx.tcx.def_span(field.did))
2540                            .nested(err)
2541                    }
2542                })
2543            });
2544
2545            // Check if this ADT has a constrained layout (like `NonNull` and friends).
2546            if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) {
2547                if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
2548                    &layout.backend_repr
2549                {
2550                    let range = scalar.valid_range(cx);
2551                    let msg = if !range.contains(0) {
2552                        "must be non-null"
2553                    } else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
2554                        // Prefer reporting on the fields over the entire struct for uninit,
2555                        // as the information bubbles out and it may be unclear why the type can't
2556                        // be null from just its outside signature.
2557
2558                        "must be initialized inside its custom valid range"
2559                    } else {
2560                        return field_err;
2561                    };
2562                    if let Some(field_err) = &mut field_err {
2563                        // Most of the time, if the field error is the same as the struct error,
2564                        // the struct error only happens because of the field error.
2565                        if field_err.message.contains(msg) {
2566                            field_err.message = format!("because {}", field_err.message);
2567                        }
2568                    }
2569                    return Some(InitError::from(format!("`{ty}` {msg}")).nested(field_err));
2570                }
2571            }
2572            field_err
2573        }
2574
2575        /// Return `Some` only if we are sure this type does *not*
2576        /// allow zero initialization.
2577        fn ty_find_init_error<'tcx>(
2578            cx: &LateContext<'tcx>,
2579            ty: Ty<'tcx>,
2580            init: InitKind,
2581        ) -> Option<InitError> {
2582            let ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty);
2583
2584            match ty.kind() {
2585                // Primitive types that don't like 0 as a value.
2586                ty::Ref(..) => Some("references must be non-null".into()),
2587                ty::Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()),
2588                ty::FnPtr(..) => Some("function pointers must be non-null".into()),
2589                ty::Never => Some("the `!` type has no valid value".into()),
2590                ty::RawPtr(ty, _) if matches!(ty.kind(), ty::Dynamic(..)) =>
2591                // raw ptr to dyn Trait
2592                {
2593                    Some("the vtable of a wide raw pointer must be non-null".into())
2594                }
2595                // Primitive types with other constraints.
2596                ty::Bool if init == InitKind::Uninit => {
2597                    Some("booleans must be either `true` or `false`".into())
2598                }
2599                ty::Char if init == InitKind::Uninit => {
2600                    Some("characters must be a valid Unicode codepoint".into())
2601                }
2602                ty::Int(_) | ty::Uint(_) if init == InitKind::Uninit => {
2603                    Some("integers must be initialized".into())
2604                }
2605                ty::Float(_) if init == InitKind::Uninit => {
2606                    Some("floats must be initialized".into())
2607                }
2608                ty::RawPtr(_, _) if init == InitKind::Uninit => {
2609                    Some("raw pointers must be initialized".into())
2610                }
2611                // Recurse and checks for some compound types. (but not unions)
2612                ty::Adt(adt_def, args) if !adt_def.is_union() => {
2613                    // Handle structs.
2614                    if adt_def.is_struct() {
2615                        return variant_find_init_error(
2616                            cx,
2617                            ty,
2618                            adt_def.non_enum_variant(),
2619                            args,
2620                            "struct field",
2621                            init,
2622                        );
2623                    }
2624                    // And now, enums.
2625                    let span = cx.tcx.def_span(adt_def.did());
2626                    let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
2627                        let definitely_inhabited = match variant
2628                            .inhabited_predicate(cx.tcx, *adt_def)
2629                            .instantiate(cx.tcx, args)
2630                            .apply_any_module(cx.tcx, cx.typing_env())
2631                        {
2632                            // Entirely skip uninhabited variants.
2633                            Some(false) => return None,
2634                            // Forward the others, but remember which ones are definitely inhabited.
2635                            Some(true) => true,
2636                            None => false,
2637                        };
2638                        Some((variant, definitely_inhabited))
2639                    });
2640                    let Some(first_variant) = potential_variants.next() else {
2641                        return Some(
2642                            InitError::from("enums with no inhabited variants have no valid value")
2643                                .spanned(span),
2644                        );
2645                    };
2646                    // So we have at least one potentially inhabited variant. Might we have two?
2647                    let Some(second_variant) = potential_variants.next() else {
2648                        // There is only one potentially inhabited variant. So we can recursively
2649                        // check that variant!
2650                        return variant_find_init_error(
2651                            cx,
2652                            ty,
2653                            first_variant.0,
2654                            args,
2655                            "field of the only potentially inhabited enum variant",
2656                            init,
2657                        );
2658                    };
2659                    // So we have at least two potentially inhabited variants. If we can prove that
2660                    // we have at least two *definitely* inhabited variants, then we have a tag and
2661                    // hence leaving this uninit is definitely disallowed. (Leaving it zeroed could
2662                    // be okay, depending on which variant is encoded as zero tag.)
2663                    if init == InitKind::Uninit {
2664                        let definitely_inhabited = (first_variant.1 as usize)
2665                            + (second_variant.1 as usize)
2666                            + potential_variants
2667                                .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
2668                                .count();
2669                        if definitely_inhabited > 1 {
2670                            return Some(InitError::from(
2671                                "enums with multiple inhabited variants have to be initialized to a variant",
2672                            ).spanned(span));
2673                        }
2674                    }
2675                    // We couldn't find anything wrong here.
2676                    None
2677                }
2678                ty::Tuple(..) => {
2679                    // Proceed recursively, check all fields.
2680                    ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2681                }
2682                ty::Array(ty, len) => {
2683                    if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) {
2684                        // Array length known at array non-empty -- recurse.
2685                        ty_find_init_error(cx, *ty, init)
2686                    } else {
2687                        // Empty array or size unknown.
2688                        None
2689                    }
2690                }
2691                // Conservative fallback.
2692                _ => None,
2693            }
2694        }
2695
2696        if let Some(init) = is_dangerous_init(cx, expr) {
2697            // This conjures an instance of a type out of nothing,
2698            // using zeroed or uninitialized memory.
2699            // We are extremely conservative with what we warn about.
2700            let conjured_ty = cx.typeck_results().expr_ty(expr);
2701            if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
2702                let msg = match init {
2703                    InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
2704                    InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
2705                };
2706                let sub = BuiltinUnpermittedTypeInitSub { err };
2707                cx.emit_span_lint(
2708                    INVALID_VALUE,
2709                    expr.span,
2710                    BuiltinUnpermittedTypeInit {
2711                        msg,
2712                        ty: conjured_ty,
2713                        label: expr.span,
2714                        sub,
2715                        tcx: cx.tcx,
2716                    },
2717                );
2718            }
2719        }
2720    }
2721}
2722
2723declare_lint! {
2724    /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
2725    /// which causes [undefined behavior].
2726    ///
2727    /// ### Example
2728    ///
2729    /// ```rust,no_run
2730    /// # #![allow(unused)]
2731    /// use std::ptr;
2732    /// unsafe {
2733    ///     let x = &*ptr::null::<i32>();
2734    ///     let x = ptr::addr_of!(*ptr::null::<i32>());
2735    ///     let x = *(0 as *const i32);
2736    /// }
2737    /// ```
2738    ///
2739    /// {{produces}}
2740    ///
2741    /// ### Explanation
2742    ///
2743    /// Dereferencing a null pointer causes [undefined behavior] if it is accessed
2744    /// (loaded from or stored to).
2745    ///
2746    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2747    pub DEREF_NULLPTR,
2748    Warn,
2749    "detects when an null pointer is dereferenced"
2750}
2751
2752declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
2753
2754impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
2755    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2756        /// test if expression is a null ptr
2757        fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
2758            match &expr.kind {
2759                hir::ExprKind::Cast(expr, ty) => {
2760                    if let hir::TyKind::Ptr(_) = ty.kind {
2761                        return is_zero(expr) || is_null_ptr(cx, expr);
2762                    }
2763                }
2764                // check for call to `core::ptr::null` or `core::ptr::null_mut`
2765                hir::ExprKind::Call(path, _) => {
2766                    if let hir::ExprKind::Path(ref qpath) = path.kind {
2767                        if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
2768                            return matches!(
2769                                cx.tcx.get_diagnostic_name(def_id),
2770                                Some(sym::ptr_null | sym::ptr_null_mut)
2771                            );
2772                        }
2773                    }
2774                }
2775                _ => {}
2776            }
2777            false
2778        }
2779
2780        /// test if expression is the literal `0`
2781        fn is_zero(expr: &hir::Expr<'_>) -> bool {
2782            match &expr.kind {
2783                hir::ExprKind::Lit(lit) => {
2784                    if let LitKind::Int(a, _) = lit.node {
2785                        return a == 0;
2786                    }
2787                }
2788                _ => {}
2789            }
2790            false
2791        }
2792
2793        if let hir::ExprKind::Unary(hir::UnOp::Deref, expr_deref) = expr.kind
2794            && is_null_ptr(cx, expr_deref)
2795        {
2796            if let hir::Node::Expr(hir::Expr {
2797                kind: hir::ExprKind::AddrOf(hir::BorrowKind::Raw, ..),
2798                ..
2799            }) = cx.tcx.parent_hir_node(expr.hir_id)
2800            {
2801                // `&raw *NULL` is ok.
2802            } else {
2803                cx.emit_span_lint(
2804                    DEREF_NULLPTR,
2805                    expr.span,
2806                    BuiltinDerefNullptr { label: expr.span },
2807                );
2808            }
2809        }
2810    }
2811}
2812
2813declare_lint! {
2814    /// The `named_asm_labels` lint detects the use of named labels in the
2815    /// inline `asm!` macro.
2816    ///
2817    /// ### Example
2818    ///
2819    /// ```rust,compile_fail
2820    /// # #![feature(asm_experimental_arch)]
2821    /// use std::arch::asm;
2822    ///
2823    /// fn main() {
2824    ///     unsafe {
2825    ///         asm!("foo: bar");
2826    ///     }
2827    /// }
2828    /// ```
2829    ///
2830    /// {{produces}}
2831    ///
2832    /// ### Explanation
2833    ///
2834    /// LLVM is allowed to duplicate inline assembly blocks for any
2835    /// reason, for example when it is in a function that gets inlined. Because
2836    /// of this, GNU assembler [local labels] *must* be used instead of labels
2837    /// with a name. Using named labels might cause assembler or linker errors.
2838    ///
2839    /// See the explanation in [Rust By Example] for more details.
2840    ///
2841    /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
2842    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2843    pub NAMED_ASM_LABELS,
2844    Deny,
2845    "named labels in inline assembly",
2846}
2847
2848declare_lint! {
2849    /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary
2850    /// digits in the inline `asm!` macro.
2851    ///
2852    /// ### Example
2853    ///
2854    /// ```rust,ignore (fails on non-x86_64)
2855    /// #![cfg(target_arch = "x86_64")]
2856    ///
2857    /// use std::arch::asm;
2858    ///
2859    /// fn main() {
2860    ///     unsafe {
2861    ///         asm!("0: jmp 0b");
2862    ///     }
2863    /// }
2864    /// ```
2865    ///
2866    /// This will produce:
2867    ///
2868    /// ```text
2869    /// error: avoid using labels containing only the digits `0` and `1` in inline assembly
2870    ///  --> <source>:7:15
2871    ///   |
2872    /// 7 |         asm!("0: jmp 0b");
2873    ///   |               ^ use a different label that doesn't start with `0` or `1`
2874    ///   |
2875    ///   = help: start numbering with `2` instead
2876    ///   = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86
2877    ///   = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information
2878    ///   = note: `#[deny(binary_asm_labels)]` on by default
2879    /// ```
2880    ///
2881    /// ### Explanation
2882    ///
2883    /// An [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary
2884    /// literal instead of a reference to the previous local label `0`. To work around this bug,
2885    /// don't use labels that could be confused with a binary literal.
2886    ///
2887    /// This behavior is platform-specific to x86 and x86-64.
2888    ///
2889    /// See the explanation in [Rust By Example] for more details.
2890    ///
2891    /// [LLVM bug]: https://github.com/llvm/llvm-project/issues/99547
2892    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2893    pub BINARY_ASM_LABELS,
2894    Deny,
2895    "labels in inline assembly containing only 0 or 1 digits",
2896}
2897
2898declare_lint_pass!(AsmLabels => [NAMED_ASM_LABELS, BINARY_ASM_LABELS]);
2899
2900#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2901enum AsmLabelKind {
2902    Named,
2903    FormatArg,
2904    Binary,
2905}
2906
2907impl<'tcx> LateLintPass<'tcx> for AsmLabels {
2908    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
2909        if let hir::Expr {
2910            kind:
2911                hir::ExprKind::InlineAsm(hir::InlineAsm {
2912                    asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
2913                    template_strs,
2914                    options,
2915                    ..
2916                }),
2917            ..
2918        } = expr
2919        {
2920            // asm with `options(raw)` does not do replacement with `{` and `}`.
2921            let raw = options.contains(InlineAsmOptions::RAW);
2922
2923            for (template_sym, template_snippet, template_span) in template_strs.iter() {
2924                let template_str = template_sym.as_str();
2925                let find_label_span = |needle: &str| -> Option<Span> {
2926                    if let Some(template_snippet) = template_snippet {
2927                        let snippet = template_snippet.as_str();
2928                        if let Some(pos) = snippet.find(needle) {
2929                            let end = pos
2930                                + snippet[pos..]
2931                                    .find(|c| c == ':')
2932                                    .unwrap_or(snippet[pos..].len() - 1);
2933                            let inner = InnerSpan::new(pos, end);
2934                            return Some(template_span.from_inner(inner));
2935                        }
2936                    }
2937
2938                    None
2939                };
2940
2941                // diagnostics are emitted per-template, so this is created here as opposed to the outer loop
2942                let mut spans = Vec::new();
2943
2944                // A semicolon might not actually be specified as a separator for all targets, but
2945                // it seems like LLVM accepts it always.
2946                let statements = template_str.split(|c| matches!(c, '\n' | ';'));
2947                for statement in statements {
2948                    // If there's a comment, trim it from the statement
2949                    let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
2950
2951                    // In this loop, if there is ever a non-label, no labels can come after it.
2952                    let mut start_idx = 0;
2953                    'label_loop: for (idx, _) in statement.match_indices(':') {
2954                        let possible_label = statement[start_idx..idx].trim();
2955                        let mut chars = possible_label.chars();
2956
2957                        let Some(start) = chars.next() else {
2958                            // Empty string means a leading ':' in this section, which is not a
2959                            // label.
2960                            break 'label_loop;
2961                        };
2962
2963                        // Whether a { bracket has been seen and its } hasn't been found yet.
2964                        let mut in_bracket = false;
2965                        let mut label_kind = AsmLabelKind::Named;
2966
2967                        // A label can also start with a format arg, if it's not a raw asm block.
2968                        if !raw && start == '{' {
2969                            in_bracket = true;
2970                            label_kind = AsmLabelKind::FormatArg;
2971                        } else if matches!(start, '0' | '1') {
2972                            // Binary labels have only the characters `0` or `1`.
2973                            label_kind = AsmLabelKind::Binary;
2974                        } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) {
2975                            // Named labels start with ASCII letters, `.` or `_`.
2976                            // anything else is not a label
2977                            break 'label_loop;
2978                        }
2979
2980                        for c in chars {
2981                            // Inside a template format arg, any character is permitted for the
2982                            // puproses of label detection because we assume that it can be
2983                            // replaced with some other valid label string later. `options(raw)`
2984                            // asm blocks cannot have format args, so they are excluded from this
2985                            // special case.
2986                            if !raw && in_bracket {
2987                                if c == '{' {
2988                                    // Nested brackets are not allowed in format args, this cannot
2989                                    // be a label.
2990                                    break 'label_loop;
2991                                }
2992
2993                                if c == '}' {
2994                                    // The end of the format arg.
2995                                    in_bracket = false;
2996                                }
2997                            } else if !raw && c == '{' {
2998                                // Start of a format arg.
2999                                in_bracket = true;
3000                                label_kind = AsmLabelKind::FormatArg;
3001                            } else {
3002                                let can_continue = match label_kind {
3003                                    // Format arg labels are considered to be named labels for the purposes
3004                                    // of continuing outside of their {} pair.
3005                                    AsmLabelKind::Named | AsmLabelKind::FormatArg => {
3006                                        c.is_ascii_alphanumeric() || matches!(c, '_' | '$')
3007                                    }
3008                                    AsmLabelKind::Binary => matches!(c, '0' | '1'),
3009                                };
3010
3011                                if !can_continue {
3012                                    // The potential label had an invalid character inside it, it
3013                                    // cannot be a label.
3014                                    break 'label_loop;
3015                                }
3016                            }
3017                        }
3018
3019                        // If all characters passed the label checks, this is a label.
3020                        spans.push((find_label_span(possible_label), label_kind));
3021                        start_idx = idx + 1;
3022                    }
3023                }
3024
3025                for (span, label_kind) in spans {
3026                    let missing_precise_span = span.is_none();
3027                    let span = span.unwrap_or(*template_span);
3028                    match label_kind {
3029                        AsmLabelKind::Named => {
3030                            cx.emit_span_lint(
3031                                NAMED_ASM_LABELS,
3032                                span,
3033                                InvalidAsmLabel::Named { missing_precise_span },
3034                            );
3035                        }
3036                        AsmLabelKind::FormatArg => {
3037                            cx.emit_span_lint(
3038                                NAMED_ASM_LABELS,
3039                                span,
3040                                InvalidAsmLabel::FormatArg { missing_precise_span },
3041                            );
3042                        }
3043                        // the binary asm issue only occurs when using intel syntax on x86 targets
3044                        AsmLabelKind::Binary
3045                            if !options.contains(InlineAsmOptions::ATT_SYNTAX)
3046                                && matches!(
3047                                    cx.tcx.sess.asm_arch,
3048                                    Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None
3049                                ) =>
3050                        {
3051                            cx.emit_span_lint(
3052                                BINARY_ASM_LABELS,
3053                                span,
3054                                InvalidAsmLabel::Binary { missing_precise_span, span },
3055                            )
3056                        }
3057                        // No lint on anything other than x86
3058                        AsmLabelKind::Binary => (),
3059                    };
3060                }
3061            }
3062        }
3063    }
3064}
3065
3066declare_lint! {
3067    /// The `special_module_name` lint detects module
3068    /// declarations for files that have a special meaning.
3069    ///
3070    /// ### Example
3071    ///
3072    /// ```rust,compile_fail
3073    /// mod lib;
3074    ///
3075    /// fn main() {
3076    ///     lib::run();
3077    /// }
3078    /// ```
3079    ///
3080    /// {{produces}}
3081    ///
3082    /// ### Explanation
3083    ///
3084    /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
3085    /// library or binary crate, so declaring them as modules
3086    /// will lead to miscompilation of the crate unless configured
3087    /// explicitly.
3088    ///
3089    /// To access a library from a binary target within the same crate,
3090    /// use `your_crate_name::` as the path instead of `lib::`:
3091    ///
3092    /// ```rust,compile_fail
3093    /// // bar/src/lib.rs
3094    /// fn run() {
3095    ///     // ...
3096    /// }
3097    ///
3098    /// // bar/src/main.rs
3099    /// fn main() {
3100    ///     bar::run();
3101    /// }
3102    /// ```
3103    ///
3104    /// Binary targets cannot be used as libraries and so declaring
3105    /// one as a module is not allowed.
3106    pub SPECIAL_MODULE_NAME,
3107    Warn,
3108    "module declarations for files with a special meaning",
3109}
3110
3111declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
3112
3113impl EarlyLintPass for SpecialModuleName {
3114    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
3115        for item in &krate.items {
3116            if let ast::ItemKind::Mod(
3117                _,
3118                ident,
3119                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
3120            ) = item.kind
3121            {
3122                if item.attrs.iter().any(|a| a.has_name(sym::path)) {
3123                    continue;
3124                }
3125
3126                match ident.name.as_str() {
3127                    "lib" => cx.emit_span_lint(
3128                        SPECIAL_MODULE_NAME,
3129                        item.span,
3130                        BuiltinSpecialModuleNameUsed::Lib,
3131                    ),
3132                    "main" => cx.emit_span_lint(
3133                        SPECIAL_MODULE_NAME,
3134                        item.span,
3135                        BuiltinSpecialModuleNameUsed::Main,
3136                    ),
3137                    _ => continue,
3138                }
3139            }
3140        }
3141    }
3142}