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(_, generics, _) => {
549                if !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(_, generics, _) => {
556                if !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(_, generics, _) => {
563                if !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    /// #[unsafe(export_name = "bar")]
981    /// fn bar<T>(t: T) {}
982    /// ```
983    ///
984    /// {{produces}}
985    ///
986    /// ### Explanation
987    ///
988    /// A function with generics must have its symbol mangled to accommodate
989    /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes
990    /// have no effect in this situation, and should be removed.
991    ///
992    /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
993    /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute
994    NO_MANGLE_GENERIC_ITEMS,
995    Warn,
996    "generic items must be mangled"
997}
998
999declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
1000
1001impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
1002    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1003        let attrs = cx.tcx.hir_attrs(it.hir_id());
1004        let check_no_mangle_on_generic_fn = |attr: &hir::Attribute,
1005                                             impl_generics: Option<&hir::Generics<'_>>,
1006                                             generics: &hir::Generics<'_>,
1007                                             span| {
1008            for param in
1009                generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1010            {
1011                match param.kind {
1012                    GenericParamKind::Lifetime { .. } => {}
1013                    GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1014                        cx.emit_span_lint(
1015                            NO_MANGLE_GENERIC_ITEMS,
1016                            span,
1017                            BuiltinNoMangleGeneric { suggestion: attr.span() },
1018                        );
1019                        break;
1020                    }
1021                }
1022            }
1023        };
1024        match it.kind {
1025            hir::ItemKind::Fn { generics, .. } => {
1026                if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
1027                    .or_else(|| attr::find_by_name(attrs, sym::no_mangle))
1028                {
1029                    check_no_mangle_on_generic_fn(attr, None, generics, it.span);
1030                }
1031            }
1032            hir::ItemKind::Const(..) => {
1033                if attr::contains_name(attrs, sym::no_mangle) {
1034                    // account for "pub const" (#45562)
1035                    let start = cx
1036                        .tcx
1037                        .sess
1038                        .source_map()
1039                        .span_to_snippet(it.span)
1040                        .map(|snippet| snippet.find("const").unwrap_or(0))
1041                        .unwrap_or(0) as u32;
1042                    // `const` is 5 chars
1043                    let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1044
1045                    // Const items do not refer to a particular location in memory, and therefore
1046                    // don't have anything to attach a symbol to
1047                    cx.emit_span_lint(
1048                        NO_MANGLE_CONST_ITEMS,
1049                        it.span,
1050                        BuiltinConstNoMangle { suggestion },
1051                    );
1052                }
1053            }
1054            hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1055                for it in *items {
1056                    if let hir::AssocItemKind::Fn { .. } = it.kind {
1057                        let attrs = cx.tcx.hir_attrs(it.id.hir_id());
1058                        if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
1059                            .or_else(|| attr::find_by_name(attrs, sym::no_mangle))
1060                        {
1061                            check_no_mangle_on_generic_fn(
1062                                attr,
1063                                Some(generics),
1064                                cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
1065                                it.span,
1066                            );
1067                        }
1068                    }
1069                }
1070            }
1071            _ => {}
1072        }
1073    }
1074}
1075
1076declare_lint! {
1077    /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1078    /// T` because it is [undefined behavior].
1079    ///
1080    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1081    ///
1082    /// ### Example
1083    ///
1084    /// ```rust,compile_fail
1085    /// unsafe {
1086    ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);
1087    /// }
1088    /// ```
1089    ///
1090    /// {{produces}}
1091    ///
1092    /// ### Explanation
1093    ///
1094    /// Certain assumptions are made about aliasing of data, and this transmute
1095    /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1096    ///
1097    /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1098    MUTABLE_TRANSMUTES,
1099    Deny,
1100    "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1101}
1102
1103declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1104
1105impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1106    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1107        if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =
1108            get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1109        {
1110            if from_mutbl < to_mutbl {
1111                cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
1112            }
1113        }
1114
1115        fn get_transmute_from_to<'tcx>(
1116            cx: &LateContext<'tcx>,
1117            expr: &hir::Expr<'_>,
1118        ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1119            let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1120                cx.qpath_res(qpath, expr.hir_id)
1121            } else {
1122                return None;
1123            };
1124            if let Res::Def(DefKind::Fn, did) = def {
1125                if !def_id_is_transmute(cx, did) {
1126                    return None;
1127                }
1128                let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1129                let from = sig.inputs().skip_binder()[0];
1130                let to = sig.output().skip_binder();
1131                return Some((from, to));
1132            }
1133            None
1134        }
1135
1136        fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1137            cx.tcx.is_intrinsic(def_id, sym::transmute)
1138        }
1139    }
1140}
1141
1142declare_lint! {
1143    /// The `unstable_features` lint detects uses of `#![feature]`.
1144    ///
1145    /// ### Example
1146    ///
1147    /// ```rust,compile_fail
1148    /// #![deny(unstable_features)]
1149    /// #![feature(test)]
1150    /// ```
1151    ///
1152    /// {{produces}}
1153    ///
1154    /// ### Explanation
1155    ///
1156    /// In larger nightly-based projects which
1157    ///
1158    /// * consist of a multitude of crates where a subset of crates has to compile on
1159    ///   stable either unconditionally or depending on a `cfg` flag to for example
1160    ///   allow stable users to depend on them,
1161    /// * don't use nightly for experimental features but for, e.g., unstable options only,
1162    ///
1163    /// this lint may come in handy to enforce policies of these kinds.
1164    UNSTABLE_FEATURES,
1165    Allow,
1166    "enabling unstable features"
1167}
1168
1169declare_lint_pass!(
1170    /// Forbids using the `#[feature(...)]` attribute
1171    UnstableFeatures => [UNSTABLE_FEATURES]
1172);
1173
1174impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1175    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
1176        if attr.has_name(sym::feature)
1177            && let Some(items) = attr.meta_item_list()
1178        {
1179            for item in items {
1180                cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
1181            }
1182        }
1183    }
1184}
1185
1186declare_lint! {
1187    /// The `ungated_async_fn_track_caller` lint warns when the
1188    /// `#[track_caller]` attribute is used on an async function
1189    /// without enabling the corresponding unstable feature flag.
1190    ///
1191    /// ### Example
1192    ///
1193    /// ```rust
1194    /// #[track_caller]
1195    /// async fn foo() {}
1196    /// ```
1197    ///
1198    /// {{produces}}
1199    ///
1200    /// ### Explanation
1201    ///
1202    /// The attribute must be used in conjunction with the
1203    /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`
1204    /// annotation will function as a no-op.
1205    ///
1206    /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html
1207    UNGATED_ASYNC_FN_TRACK_CALLER,
1208    Warn,
1209    "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"
1210}
1211
1212declare_lint_pass!(
1213    /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to
1214    /// do anything
1215    UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER]
1216);
1217
1218impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
1219    fn check_fn(
1220        &mut self,
1221        cx: &LateContext<'_>,
1222        fn_kind: HirFnKind<'_>,
1223        _: &'tcx FnDecl<'_>,
1224        _: &'tcx Body<'_>,
1225        span: Span,
1226        def_id: LocalDefId,
1227    ) {
1228        if fn_kind.asyncness().is_async()
1229            && !cx.tcx.features().async_fn_track_caller()
1230            // Now, check if the function has the `#[track_caller]` attribute
1231            && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
1232        {
1233            cx.emit_span_lint(
1234                UNGATED_ASYNC_FN_TRACK_CALLER,
1235                attr.span(),
1236                BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
1237            );
1238        }
1239    }
1240}
1241
1242declare_lint! {
1243    /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that
1244    /// means neither directly accessible, nor reexported (with `pub use`), nor leaked through
1245    /// things like return types (which the [`unnameable_types`] lint can detect if desired).
1246    ///
1247    /// ### Example
1248    ///
1249    /// ```rust,compile_fail
1250    /// #![deny(unreachable_pub)]
1251    /// mod foo {
1252    ///     pub mod bar {
1253    ///
1254    ///     }
1255    /// }
1256    /// ```
1257    ///
1258    /// {{produces}}
1259    ///
1260    /// ### Explanation
1261    ///
1262    /// The `pub` keyword both expresses an intent for an item to be publicly available, and also
1263    /// signals to the compiler to make the item publicly accessible. The intent can only be
1264    /// satisfied, however, if all items which contain this item are *also* publicly accessible.
1265    /// Thus, this lint serves to identify situations where the intent does not match the reality.
1266    ///
1267    /// If you wish the item to be accessible elsewhere within the crate, but not outside it, the
1268    /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the
1269    /// intent that the item is only visible within its own crate.
1270    ///
1271    /// This lint is "allow" by default because it will trigger for a large amount of existing Rust code.
1272    /// Eventually it is desired for this to become warn-by-default.
1273    ///
1274    /// [`unnameable_types`]: #unnameable-types
1275    pub UNREACHABLE_PUB,
1276    Allow,
1277    "`pub` items not reachable from crate root"
1278}
1279
1280declare_lint_pass!(
1281    /// Lint for items marked `pub` that aren't reachable from other crates.
1282    UnreachablePub => [UNREACHABLE_PUB]
1283);
1284
1285impl UnreachablePub {
1286    fn perform_lint(
1287        &self,
1288        cx: &LateContext<'_>,
1289        what: &str,
1290        def_id: LocalDefId,
1291        vis_span: Span,
1292        exportable: bool,
1293    ) {
1294        let mut applicability = Applicability::MachineApplicable;
1295        if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
1296        {
1297            // prefer suggesting `pub(super)` instead of `pub(crate)` when possible,
1298            // except when `pub(super) == pub(crate)`
1299            let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) =
1300                cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| {
1301                    effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable)
1302                })
1303                && let parent_parent = cx
1304                    .tcx
1305                    .parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into())
1306                && *restricted_did == parent_parent.to_local_def_id()
1307                && !restricted_did.to_def_id().is_crate_root()
1308            {
1309                "pub(super)"
1310            } else {
1311                "pub(crate)"
1312            };
1313
1314            if vis_span.from_expansion() {
1315                applicability = Applicability::MaybeIncorrect;
1316            }
1317            let def_span = cx.tcx.def_span(def_id);
1318            cx.emit_span_lint(
1319                UNREACHABLE_PUB,
1320                def_span,
1321                BuiltinUnreachablePub {
1322                    what,
1323                    new_vis,
1324                    suggestion: (vis_span, applicability),
1325                    help: exportable,
1326                },
1327            );
1328        }
1329    }
1330}
1331
1332impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1333    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1334        // Do not warn for fake `use` statements.
1335        if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1336            return;
1337        }
1338        self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
1339    }
1340
1341    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
1342        self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
1343    }
1344
1345    fn check_field_def(&mut self, _cx: &LateContext<'_>, _field: &hir::FieldDef<'_>) {
1346        // - If an ADT definition is reported then we don't need to check fields
1347        //   (as it would add unnecessary complexity to the source code, the struct
1348        //   definition is in the immediate proximity to give the "real" visibility).
1349        // - If an ADT is not reported because it's not `pub` - we don't need to
1350        //   check fields.
1351        // - If an ADT is not reported because it's reachable - we also don't need
1352        //   to check fields because then they are reachable by construction if they
1353        //   are pub.
1354        //
1355        // Therefore in no case we check the fields.
1356        //
1357        // cf. https://github.com/rust-lang/rust/pull/126013#issuecomment-2152839205
1358        // cf. https://github.com/rust-lang/rust/pull/126040#issuecomment-2152944506
1359    }
1360
1361    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
1362        // Only lint inherent impl items.
1363        if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
1364            self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
1365        }
1366    }
1367}
1368
1369declare_lint! {
1370    /// The `type_alias_bounds` lint detects bounds in type aliases.
1371    ///
1372    /// ### Example
1373    ///
1374    /// ```rust
1375    /// type SendVec<T: Send> = Vec<T>;
1376    /// ```
1377    ///
1378    /// {{produces}}
1379    ///
1380    /// ### Explanation
1381    ///
1382    /// Trait and lifetime bounds on generic parameters and in where clauses of
1383    /// type aliases are not checked at usage sites of the type alias. Moreover,
1384    /// they are not thoroughly checked for correctness at their definition site
1385    /// either similar to the aliased type.
1386    ///
1387    /// This is a known limitation of the type checker that may be lifted in a
1388    /// future edition. Permitting such bounds in light of this was unintentional.
1389    ///
1390    /// While these bounds may have secondary effects such as enabling the use of
1391    /// "shorthand" associated type paths[^1] and affecting the default trait
1392    /// object lifetime[^2] of trait object types passed to the type alias, this
1393    /// should not have been allowed until the aforementioned restrictions of the
1394    /// type checker have been lifted.
1395    ///
1396    /// Using such bounds is highly discouraged as they are actively misleading.
1397    ///
1398    /// [^1]: I.e., paths of the form `T::Assoc` where `T` is a type parameter
1399    /// bounded by trait `Trait` which defines an associated type called `Assoc`
1400    /// as opposed to a fully qualified path of the form `<T as Trait>::Assoc`.
1401    /// [^2]: <https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes>
1402    TYPE_ALIAS_BOUNDS,
1403    Warn,
1404    "bounds in type aliases are not enforced"
1405}
1406
1407declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]);
1408
1409impl TypeAliasBounds {
1410    pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool {
1411        // Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults.
1412        if let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind
1413            && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_)))
1414            && pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS
1415            && pred.bounded_ty.as_generic_param().is_some()
1416        {
1417            return true;
1418        }
1419        false
1420    }
1421}
1422
1423impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1424    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1425        let hir::ItemKind::TyAlias(_, generics, hir_ty) = item.kind else { return };
1426
1427        // There must not be a where clause.
1428        if generics.predicates.is_empty() {
1429            return;
1430        }
1431
1432        // Bounds of lazy type aliases and TAITs are respected.
1433        if cx.tcx.type_alias_is_lazy(item.owner_id) {
1434            return;
1435        }
1436
1437        // FIXME(generic_const_exprs): Revisit this before stabilization.
1438        // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`.
1439        let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
1440        if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
1441            && cx.tcx.features().generic_const_exprs()
1442        {
1443            return;
1444        }
1445
1446        // NOTE(inherent_associated_types): While we currently do take some bounds in type
1447        // aliases into consideration during IAT *selection*, we don't perform full use+def
1448        // site wfchecking for such type aliases. Therefore TAB should still trigger.
1449        // See also `tests/ui/associated-inherent-types/type-alias-bounds.rs`.
1450
1451        let mut where_spans = Vec::new();
1452        let mut inline_spans = Vec::new();
1453        let mut inline_sugg = Vec::new();
1454
1455        for p in generics.predicates {
1456            let span = p.span;
1457            if p.kind.in_where_clause() {
1458                where_spans.push(span);
1459            } else {
1460                for b in p.kind.bounds() {
1461                    inline_spans.push(b.span());
1462                }
1463                inline_sugg.push((span, String::new()));
1464            }
1465        }
1466
1467        let mut ty = Some(hir_ty);
1468        let enable_feat_help = cx.tcx.sess.is_nightly_build();
1469
1470        if let [.., label_sp] = *where_spans {
1471            cx.emit_span_lint(
1472                TYPE_ALIAS_BOUNDS,
1473                where_spans,
1474                BuiltinTypeAliasBounds {
1475                    in_where_clause: true,
1476                    label: label_sp,
1477                    enable_feat_help,
1478                    suggestions: vec![(generics.where_clause_span, String::new())],
1479                    preds: generics.predicates,
1480                    ty: ty.take(),
1481                },
1482            );
1483        }
1484        if let [.., label_sp] = *inline_spans {
1485            cx.emit_span_lint(
1486                TYPE_ALIAS_BOUNDS,
1487                inline_spans,
1488                BuiltinTypeAliasBounds {
1489                    in_where_clause: false,
1490                    label: label_sp,
1491                    enable_feat_help,
1492                    suggestions: inline_sugg,
1493                    preds: generics.predicates,
1494                    ty,
1495                },
1496            );
1497        }
1498    }
1499}
1500
1501pub(crate) struct ShorthandAssocTyCollector {
1502    pub(crate) qselves: Vec<Span>,
1503}
1504
1505impl hir::intravisit::Visitor<'_> for ShorthandAssocTyCollector {
1506    fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) {
1507        // Look for "type-parameter shorthand-associated-types". I.e., paths of the
1508        // form `T::Assoc` with `T` type param. These are reliant on trait bounds.
1509        if let hir::QPath::TypeRelative(qself, _) = qpath
1510            && qself.as_generic_param().is_some()
1511        {
1512            self.qselves.push(qself.span);
1513        }
1514        hir::intravisit::walk_qpath(self, qpath, id)
1515    }
1516}
1517
1518declare_lint! {
1519    /// The `trivial_bounds` lint detects trait bounds that don't depend on
1520    /// any type parameters.
1521    ///
1522    /// ### Example
1523    ///
1524    /// ```rust
1525    /// #![feature(trivial_bounds)]
1526    /// pub struct A where i32: Copy;
1527    /// ```
1528    ///
1529    /// {{produces}}
1530    ///
1531    /// ### Explanation
1532    ///
1533    /// Usually you would not write a trait bound that you know is always
1534    /// true, or never true. However, when using macros, the macro may not
1535    /// know whether or not the constraint would hold or not at the time when
1536    /// generating the code. Currently, the compiler does not alert you if the
1537    /// constraint is always true, and generates an error if it is never true.
1538    /// The `trivial_bounds` feature changes this to be a warning in both
1539    /// cases, giving macros more freedom and flexibility to generate code,
1540    /// while still providing a signal when writing non-macro code that
1541    /// something is amiss.
1542    ///
1543    /// See [RFC 2056] for more details. This feature is currently only
1544    /// available on the nightly channel, see [tracking issue #48214].
1545    ///
1546    /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1547    /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1548    TRIVIAL_BOUNDS,
1549    Warn,
1550    "these bounds don't depend on an type parameters"
1551}
1552
1553declare_lint_pass!(
1554    /// Lint for trait and lifetime bounds that don't depend on type parameters
1555    /// which either do nothing, or stop the item from being used.
1556    TrivialConstraints => [TRIVIAL_BOUNDS]
1557);
1558
1559impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1560    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1561        use rustc_middle::ty::ClauseKind;
1562
1563        if cx.tcx.features().trivial_bounds() {
1564            let predicates = cx.tcx.predicates_of(item.owner_id);
1565            for &(predicate, span) in predicates.predicates {
1566                let predicate_kind_name = match predicate.kind().skip_binder() {
1567                    ClauseKind::Trait(..) => "trait",
1568                    ClauseKind::TypeOutlives(..) |
1569                    ClauseKind::RegionOutlives(..) => "lifetime",
1570
1571                    // `ConstArgHasType` is never global as `ct` is always a param
1572                    ClauseKind::ConstArgHasType(..)
1573                    // Ignore projections, as they can only be global
1574                    // if the trait bound is global
1575                    | ClauseKind::Projection(..)
1576                    // Ignore bounds that a user can't type
1577                    | ClauseKind::WellFormed(..)
1578                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
1579                    | ClauseKind::ConstEvaluatable(..)
1580                    // Users don't write this directly, only via another trait ref.
1581                    | ty::ClauseKind::HostEffect(..) => continue,
1582                };
1583                if predicate.is_global() {
1584                    cx.emit_span_lint(
1585                        TRIVIAL_BOUNDS,
1586                        span,
1587                        BuiltinTrivialBounds { predicate_kind_name, predicate },
1588                    );
1589                }
1590            }
1591        }
1592    }
1593}
1594
1595declare_lint! {
1596    /// The `double_negations` lint detects expressions of the form `--x`.
1597    ///
1598    /// ### Example
1599    ///
1600    /// ```rust
1601    /// fn main() {
1602    ///     let x = 1;
1603    ///     let _b = --x;
1604    /// }
1605    /// ```
1606    ///
1607    /// {{produces}}
1608    ///
1609    /// ### Explanation
1610    ///
1611    /// Negating something twice is usually the same as not negating it at all.
1612    /// However, a double negation in Rust can easily be confused with the
1613    /// prefix decrement operator that exists in many languages derived from C.
1614    /// Use `-(-x)` if you really wanted to negate the value twice.
1615    ///
1616    /// To decrement a value, use `x -= 1` instead.
1617    pub DOUBLE_NEGATIONS,
1618    Warn,
1619    "detects expressions of the form `--x`"
1620}
1621
1622declare_lint_pass!(
1623    /// Lint for expressions of the form `--x` that can be confused with C's
1624    /// prefix decrement operator.
1625    DoubleNegations => [DOUBLE_NEGATIONS]
1626);
1627
1628impl EarlyLintPass for DoubleNegations {
1629    #[inline]
1630    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1631        // only lint on the innermost `--` in a chain of `-` operators,
1632        // even if there are 3 or more negations
1633        if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
1634            && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
1635            && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
1636        {
1637            cx.emit_span_lint(
1638                DOUBLE_NEGATIONS,
1639                expr.span,
1640                BuiltinDoubleNegations {
1641                    add_parens: BuiltinDoubleNegationsAddParens {
1642                        start_span: inner.span.shrink_to_lo(),
1643                        end_span: inner.span.shrink_to_hi(),
1644                    },
1645                },
1646            );
1647        }
1648    }
1649}
1650
1651declare_lint_pass!(
1652    /// Does nothing as a lint pass, but registers some `Lint`s
1653    /// which are used by other parts of the compiler.
1654    SoftLints => [
1655        WHILE_TRUE,
1656        NON_SHORTHAND_FIELD_PATTERNS,
1657        UNSAFE_CODE,
1658        MISSING_DOCS,
1659        MISSING_COPY_IMPLEMENTATIONS,
1660        MISSING_DEBUG_IMPLEMENTATIONS,
1661        ANONYMOUS_PARAMETERS,
1662        UNUSED_DOC_COMMENTS,
1663        NO_MANGLE_CONST_ITEMS,
1664        NO_MANGLE_GENERIC_ITEMS,
1665        MUTABLE_TRANSMUTES,
1666        UNSTABLE_FEATURES,
1667        UNREACHABLE_PUB,
1668        TYPE_ALIAS_BOUNDS,
1669        TRIVIAL_BOUNDS,
1670        DOUBLE_NEGATIONS
1671    ]
1672);
1673
1674declare_lint! {
1675    /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1676    /// pattern], which is deprecated.
1677    ///
1678    /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1679    ///
1680    /// ### Example
1681    ///
1682    /// ```rust,edition2018
1683    /// let x = 123;
1684    /// match x {
1685    ///     0...100 => {}
1686    ///     _ => {}
1687    /// }
1688    /// ```
1689    ///
1690    /// {{produces}}
1691    ///
1692    /// ### Explanation
1693    ///
1694    /// The `...` range pattern syntax was changed to `..=` to avoid potential
1695    /// confusion with the [`..` range expression]. Use the new form instead.
1696    ///
1697    /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1698    pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1699    Warn,
1700    "`...` range patterns are deprecated",
1701    @future_incompatible = FutureIncompatibleInfo {
1702        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
1703        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1704    };
1705}
1706
1707#[derive(Default)]
1708pub struct EllipsisInclusiveRangePatterns {
1709    /// If `Some(_)`, suppress all subsequent pattern
1710    /// warnings for better diagnostics.
1711    node_id: Option<ast::NodeId>,
1712}
1713
1714impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1715
1716impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1717    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1718        if self.node_id.is_some() {
1719            // Don't recursively warn about patterns inside range endpoints.
1720            return;
1721        }
1722
1723        use self::ast::PatKind;
1724        use self::ast::RangeSyntax::DotDotDot;
1725
1726        /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1727        /// corresponding to the ellipsis.
1728        fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1729            match &pat.kind {
1730                PatKind::Range(
1731                    a,
1732                    Some(b),
1733                    Spanned { span, node: RangeEnd::Included(DotDotDot) },
1734                ) => Some((a.as_deref(), b, *span)),
1735                _ => None,
1736            }
1737        }
1738
1739        let (parentheses, endpoints) = match &pat.kind {
1740            PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
1741            _ => (false, matches_ellipsis_pat(pat)),
1742        };
1743
1744        if let Some((start, end, join)) = endpoints {
1745            if parentheses {
1746                self.node_id = Some(pat.id);
1747                let end = expr_to_string(end);
1748                let replace = match start {
1749                    Some(start) => format!("&({}..={})", expr_to_string(start), end),
1750                    None => format!("&(..={end})"),
1751                };
1752                if join.edition() >= Edition::Edition2021 {
1753                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
1754                        span: pat.span,
1755                        suggestion: pat.span,
1756                        replace,
1757                    });
1758                } else {
1759                    cx.emit_span_lint(
1760                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1761                        pat.span,
1762                        BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {
1763                            suggestion: pat.span,
1764                            replace,
1765                        },
1766                    );
1767                }
1768            } else {
1769                let replace = "..=";
1770                if join.edition() >= Edition::Edition2021 {
1771                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
1772                        span: pat.span,
1773                        suggestion: join,
1774                        replace: replace.to_string(),
1775                    });
1776                } else {
1777                    cx.emit_span_lint(
1778                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1779                        join,
1780                        BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {
1781                            suggestion: join,
1782                        },
1783                    );
1784                }
1785            };
1786        }
1787    }
1788
1789    fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1790        if let Some(node_id) = self.node_id {
1791            if pat.id == node_id {
1792                self.node_id = None
1793            }
1794        }
1795    }
1796}
1797
1798declare_lint! {
1799    /// The `keyword_idents_2018` lint detects edition keywords being used as an
1800    /// identifier.
1801    ///
1802    /// ### Example
1803    ///
1804    /// ```rust,edition2015,compile_fail
1805    /// #![deny(keyword_idents_2018)]
1806    /// // edition 2015
1807    /// fn dyn() {}
1808    /// ```
1809    ///
1810    /// {{produces}}
1811    ///
1812    /// ### Explanation
1813    ///
1814    /// Rust [editions] allow the language to evolve without breaking
1815    /// backwards compatibility. This lint catches code that uses new keywords
1816    /// that are added to the language that are used as identifiers (such as a
1817    /// variable name, function name, etc.). If you switch the compiler to a
1818    /// new edition without updating the code, then it will fail to compile if
1819    /// you are using a new keyword as an identifier.
1820    ///
1821    /// You can manually change the identifiers to a non-keyword, or use a
1822    /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1823    ///
1824    /// This lint solves the problem automatically. It is "allow" by default
1825    /// because the code is perfectly valid in older editions. The [`cargo
1826    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1827    /// and automatically apply the suggested fix from the compiler (which is
1828    /// to use a raw identifier). This provides a completely automated way to
1829    /// update old code for a new edition.
1830    ///
1831    /// [editions]: https://doc.rust-lang.org/edition-guide/
1832    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1833    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1834    pub KEYWORD_IDENTS_2018,
1835    Allow,
1836    "detects edition keywords being used as an identifier",
1837    @future_incompatible = FutureIncompatibleInfo {
1838        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
1839        reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1840    };
1841}
1842
1843declare_lint! {
1844    /// The `keyword_idents_2024` lint detects edition keywords being used as an
1845    /// identifier.
1846    ///
1847    /// ### Example
1848    ///
1849    /// ```rust,edition2015,compile_fail
1850    /// #![deny(keyword_idents_2024)]
1851    /// // edition 2015
1852    /// fn gen() {}
1853    /// ```
1854    ///
1855    /// {{produces}}
1856    ///
1857    /// ### Explanation
1858    ///
1859    /// Rust [editions] allow the language to evolve without breaking
1860    /// backwards compatibility. This lint catches code that uses new keywords
1861    /// that are added to the language that are used as identifiers (such as a
1862    /// variable name, function name, etc.). If you switch the compiler to a
1863    /// new edition without updating the code, then it will fail to compile if
1864    /// you are using a new keyword as an identifier.
1865    ///
1866    /// You can manually change the identifiers to a non-keyword, or use a
1867    /// [raw identifier], for example `r#gen`, to transition to a new edition.
1868    ///
1869    /// This lint solves the problem automatically. It is "allow" by default
1870    /// because the code is perfectly valid in older editions. The [`cargo
1871    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1872    /// and automatically apply the suggested fix from the compiler (which is
1873    /// to use a raw identifier). This provides a completely automated way to
1874    /// update old code for a new edition.
1875    ///
1876    /// [editions]: https://doc.rust-lang.org/edition-guide/
1877    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1878    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1879    pub KEYWORD_IDENTS_2024,
1880    Allow,
1881    "detects edition keywords being used as an identifier",
1882    @future_incompatible = FutureIncompatibleInfo {
1883        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
1884        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/gen-keyword.html>",
1885    };
1886}
1887
1888declare_lint_pass!(
1889    /// Check for uses of edition keywords used as an identifier.
1890    KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
1891);
1892
1893struct UnderMacro(bool);
1894
1895impl KeywordIdents {
1896    fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
1897        // Check if the preceding token is `$`, because we want to allow `$async`, etc.
1898        let mut prev_dollar = false;
1899        for tt in tokens.iter() {
1900            match tt {
1901                // Only report non-raw idents.
1902                TokenTree::Token(token, _) => {
1903                    if let Some((ident, token::IdentIsRaw::No)) = token.ident() {
1904                        if !prev_dollar {
1905                            self.check_ident_token(cx, UnderMacro(true), ident, "");
1906                        }
1907                    } else if let Some((ident, token::IdentIsRaw::No)) = token.lifetime() {
1908                        self.check_ident_token(
1909                            cx,
1910                            UnderMacro(true),
1911                            ident.without_first_quote(),
1912                            "'",
1913                        );
1914                    } else if token.kind == TokenKind::Dollar {
1915                        prev_dollar = true;
1916                        continue;
1917                    }
1918                }
1919                TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
1920            }
1921            prev_dollar = false;
1922        }
1923    }
1924
1925    fn check_ident_token(
1926        &mut self,
1927        cx: &EarlyContext<'_>,
1928        UnderMacro(under_macro): UnderMacro,
1929        ident: Ident,
1930        prefix: &'static str,
1931    ) {
1932        let (lint, edition) = match ident.name {
1933            kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1934
1935            // rust-lang/rust#56327: Conservatively do not
1936            // attempt to report occurrences of `dyn` within
1937            // macro definitions or invocations, because `dyn`
1938            // can legitimately occur as a contextual keyword
1939            // in 2015 code denoting its 2018 meaning, and we
1940            // do not want rustfix to inject bugs into working
1941            // code by rewriting such occurrences.
1942            //
1943            // But if we see `dyn` outside of a macro, we know
1944            // its precise role in the parsed AST and thus are
1945            // assured this is truly an attempt to use it as
1946            // an identifier.
1947            kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
1948
1949            kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
1950
1951            _ => return,
1952        };
1953
1954        // Don't lint `r#foo`.
1955        if ident.span.edition() >= edition
1956            || cx.sess().psess.raw_identifier_spans.contains(ident.span)
1957        {
1958            return;
1959        }
1960
1961        cx.emit_span_lint(
1962            lint,
1963            ident.span,
1964            BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix },
1965        );
1966    }
1967}
1968
1969impl EarlyLintPass for KeywordIdents {
1970    fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
1971        self.check_tokens(cx, &mac_def.body.tokens);
1972    }
1973    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
1974        self.check_tokens(cx, &mac.args.tokens);
1975    }
1976    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) {
1977        if ident.name.as_str().starts_with('\'') {
1978            self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'");
1979        } else {
1980            self.check_ident_token(cx, UnderMacro(false), *ident, "");
1981        }
1982    }
1983}
1984
1985declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
1986
1987impl ExplicitOutlivesRequirements {
1988    fn lifetimes_outliving_lifetime<'tcx>(
1989        tcx: TyCtxt<'tcx>,
1990        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
1991        item: LocalDefId,
1992        lifetime: LocalDefId,
1993    ) -> Vec<ty::Region<'tcx>> {
1994        let item_generics = tcx.generics_of(item);
1995
1996        inferred_outlives
1997            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
1998                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a.kind() {
1999                    ty::ReEarlyParam(ebr)
2000                        if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() =>
2001                    {
2002                        Some(b)
2003                    }
2004                    _ => None,
2005                },
2006                _ => None,
2007            })
2008            .collect()
2009    }
2010
2011    fn lifetimes_outliving_type<'tcx>(
2012        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
2013        index: u32,
2014    ) -> Vec<ty::Region<'tcx>> {
2015        inferred_outlives
2016            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
2017                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
2018                    a.is_param(index).then_some(b)
2019                }
2020                _ => None,
2021            })
2022            .collect()
2023    }
2024
2025    fn collect_outlives_bound_spans<'tcx>(
2026        &self,
2027        tcx: TyCtxt<'tcx>,
2028        bounds: &hir::GenericBounds<'_>,
2029        inferred_outlives: &[ty::Region<'tcx>],
2030        predicate_span: Span,
2031        item: DefId,
2032    ) -> Vec<(usize, Span)> {
2033        use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
2034
2035        let item_generics = tcx.generics_of(item);
2036
2037        bounds
2038            .iter()
2039            .enumerate()
2040            .filter_map(|(i, bound)| {
2041                let hir::GenericBound::Outlives(lifetime) = bound else {
2042                    return None;
2043                };
2044
2045                let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
2046                    Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
2047                        .iter()
2048                        .any(|r| matches!(r.kind(), ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })),
2049                    _ => false,
2050                };
2051
2052                if !is_inferred {
2053                    return None;
2054                }
2055
2056                let span = bound.span().find_ancestor_inside(predicate_span)?;
2057                if span.in_external_macro(tcx.sess.source_map()) {
2058                    return None;
2059                }
2060
2061                Some((i, span))
2062            })
2063            .collect()
2064    }
2065
2066    fn consolidate_outlives_bound_spans(
2067        &self,
2068        lo: Span,
2069        bounds: &hir::GenericBounds<'_>,
2070        bound_spans: Vec<(usize, Span)>,
2071    ) -> Vec<Span> {
2072        if bounds.is_empty() {
2073            return Vec::new();
2074        }
2075        if bound_spans.len() == bounds.len() {
2076            let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
2077            // If all bounds are inferable, we want to delete the colon, so
2078            // start from just after the parameter (span passed as argument)
2079            vec![lo.to(last_bound_span)]
2080        } else {
2081            let mut merged = Vec::new();
2082            let mut last_merged_i = None;
2083
2084            let mut from_start = true;
2085            for (i, bound_span) in bound_spans {
2086                match last_merged_i {
2087                    // If the first bound is inferable, our span should also eat the leading `+`.
2088                    None if i == 0 => {
2089                        merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2090                        last_merged_i = Some(0);
2091                    }
2092                    // If consecutive bounds are inferable, merge their spans
2093                    Some(h) if i == h + 1 => {
2094                        if let Some(tail) = merged.last_mut() {
2095                            // Also eat the trailing `+` if the first
2096                            // more-than-one bound is inferable
2097                            let to_span = if from_start && i < bounds.len() {
2098                                bounds[i + 1].span().shrink_to_lo()
2099                            } else {
2100                                bound_span
2101                            };
2102                            *tail = tail.to(to_span);
2103                            last_merged_i = Some(i);
2104                        } else {
2105                            bug!("another bound-span visited earlier");
2106                        }
2107                    }
2108                    _ => {
2109                        // When we find a non-inferable bound, subsequent inferable bounds
2110                        // won't be consecutive from the start (and we'll eat the leading
2111                        // `+` rather than the trailing one)
2112                        from_start = false;
2113                        merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
2114                        last_merged_i = Some(i);
2115                    }
2116                }
2117            }
2118            merged
2119        }
2120    }
2121}
2122
2123impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2124    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
2125        use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
2126
2127        let def_id = item.owner_id.def_id;
2128        if let hir::ItemKind::Struct(_, generics, _)
2129        | hir::ItemKind::Enum(_, generics, _)
2130        | hir::ItemKind::Union(_, generics, _) = item.kind
2131        {
2132            let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2133            if inferred_outlives.is_empty() {
2134                return;
2135            }
2136
2137            let ty_generics = cx.tcx.generics_of(def_id);
2138            let num_where_predicates = generics
2139                .predicates
2140                .iter()
2141                .filter(|predicate| predicate.kind.in_where_clause())
2142                .count();
2143
2144            let mut bound_count = 0;
2145            let mut lint_spans = Vec::new();
2146            let mut where_lint_spans = Vec::new();
2147            let mut dropped_where_predicate_count = 0;
2148            for (i, where_predicate) in generics.predicates.iter().enumerate() {
2149                let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
2150                    match where_predicate.kind {
2151                        hir::WherePredicateKind::RegionPredicate(predicate) => {
2152                            if let Some(ResolvedArg::EarlyBound(region_def_id)) =
2153                                cx.tcx.named_bound_var(predicate.lifetime.hir_id)
2154                            {
2155                                (
2156                                    Self::lifetimes_outliving_lifetime(
2157                                        cx.tcx,
2158                                        // don't warn if the inferred span actually came from the predicate we're looking at
2159                                        // this happens if the type is recursively defined
2160                                        inferred_outlives.iter().filter(|(_, span)| {
2161                                            !where_predicate.span.contains(*span)
2162                                        }),
2163                                        item.owner_id.def_id,
2164                                        region_def_id,
2165                                    ),
2166                                    &predicate.bounds,
2167                                    where_predicate.span,
2168                                    predicate.in_where_clause,
2169                                )
2170                            } else {
2171                                continue;
2172                            }
2173                        }
2174                        hir::WherePredicateKind::BoundPredicate(predicate) => {
2175                            // FIXME we can also infer bounds on associated types,
2176                            // and should check for them here.
2177                            match predicate.bounded_ty.kind {
2178                                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
2179                                    let Res::Def(DefKind::TyParam, def_id) = path.res else {
2180                                        continue;
2181                                    };
2182                                    let index = ty_generics.param_def_id_to_index[&def_id];
2183                                    (
2184                                        Self::lifetimes_outliving_type(
2185                                            // don't warn if the inferred span actually came from the predicate we're looking at
2186                                            // this happens if the type is recursively defined
2187                                            inferred_outlives.iter().filter(|(_, span)| {
2188                                                !where_predicate.span.contains(*span)
2189                                            }),
2190                                            index,
2191                                        ),
2192                                        &predicate.bounds,
2193                                        where_predicate.span,
2194                                        predicate.origin == PredicateOrigin::WhereClause,
2195                                    )
2196                                }
2197                                _ => {
2198                                    continue;
2199                                }
2200                            }
2201                        }
2202                        _ => continue,
2203                    };
2204                if relevant_lifetimes.is_empty() {
2205                    continue;
2206                }
2207
2208                let bound_spans = self.collect_outlives_bound_spans(
2209                    cx.tcx,
2210                    bounds,
2211                    &relevant_lifetimes,
2212                    predicate_span,
2213                    item.owner_id.to_def_id(),
2214                );
2215                bound_count += bound_spans.len();
2216
2217                let drop_predicate = bound_spans.len() == bounds.len();
2218                if drop_predicate && in_where_clause {
2219                    dropped_where_predicate_count += 1;
2220                }
2221
2222                if drop_predicate {
2223                    if !in_where_clause {
2224                        lint_spans.push(predicate_span);
2225                    } else if predicate_span.from_expansion() {
2226                        // Don't try to extend the span if it comes from a macro expansion.
2227                        where_lint_spans.push(predicate_span);
2228                    } else if i + 1 < num_where_predicates {
2229                        // If all the bounds on a predicate were inferable and there are
2230                        // further predicates, we want to eat the trailing comma.
2231                        let next_predicate_span = generics.predicates[i + 1].span;
2232                        if next_predicate_span.from_expansion() {
2233                            where_lint_spans.push(predicate_span);
2234                        } else {
2235                            where_lint_spans
2236                                .push(predicate_span.to(next_predicate_span.shrink_to_lo()));
2237                        }
2238                    } else {
2239                        // Eat the optional trailing comma after the last predicate.
2240                        let where_span = generics.where_clause_span;
2241                        if where_span.from_expansion() {
2242                            where_lint_spans.push(predicate_span);
2243                        } else {
2244                            where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi()));
2245                        }
2246                    }
2247                } else {
2248                    where_lint_spans.extend(self.consolidate_outlives_bound_spans(
2249                        predicate_span.shrink_to_lo(),
2250                        bounds,
2251                        bound_spans,
2252                    ));
2253                }
2254            }
2255
2256            // If all predicates in where clause are inferable, drop the entire clause
2257            // (including the `where`)
2258            if generics.has_where_clause_predicates
2259                && dropped_where_predicate_count == num_where_predicates
2260            {
2261                let where_span = generics.where_clause_span;
2262                // Extend the where clause back to the closing `>` of the
2263                // generics, except for tuple struct, which have the `where`
2264                // after the fields of the struct.
2265                let full_where_span =
2266                    if let hir::ItemKind::Struct(_, _, hir::VariantData::Tuple(..)) = item.kind {
2267                        where_span
2268                    } else {
2269                        generics.span.shrink_to_hi().to(where_span)
2270                    };
2271
2272                // Due to macro expansions, the `full_where_span` might not actually contain all
2273                // predicates.
2274                if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
2275                    lint_spans.push(full_where_span);
2276                } else {
2277                    lint_spans.extend(where_lint_spans);
2278                }
2279            } else {
2280                lint_spans.extend(where_lint_spans);
2281            }
2282
2283            if !lint_spans.is_empty() {
2284                // Do not automatically delete outlives requirements from macros.
2285                let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
2286                {
2287                    Applicability::MachineApplicable
2288                } else {
2289                    Applicability::MaybeIncorrect
2290                };
2291
2292                // Due to macros, there might be several predicates with the same span
2293                // and we only want to suggest removing them once.
2294                lint_spans.sort_unstable();
2295                lint_spans.dedup();
2296
2297                cx.emit_span_lint(
2298                    EXPLICIT_OUTLIVES_REQUIREMENTS,
2299                    lint_spans.clone(),
2300                    BuiltinExplicitOutlives {
2301                        count: bound_count,
2302                        suggestion: BuiltinExplicitOutlivesSuggestion {
2303                            spans: lint_spans,
2304                            applicability,
2305                        },
2306                    },
2307                );
2308            }
2309        }
2310    }
2311}
2312
2313declare_lint! {
2314    /// The `incomplete_features` lint detects unstable features enabled with
2315    /// the [`feature` attribute] that may function improperly in some or all
2316    /// cases.
2317    ///
2318    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2319    ///
2320    /// ### Example
2321    ///
2322    /// ```rust
2323    /// #![feature(generic_const_exprs)]
2324    /// ```
2325    ///
2326    /// {{produces}}
2327    ///
2328    /// ### Explanation
2329    ///
2330    /// Although it is encouraged for people to experiment with unstable
2331    /// features, some of them are known to be incomplete or faulty. This lint
2332    /// is a signal that the feature has not yet been finished, and you may
2333    /// experience problems with it.
2334    pub INCOMPLETE_FEATURES,
2335    Warn,
2336    "incomplete features that may function improperly in some or all cases"
2337}
2338
2339declare_lint! {
2340    /// The `internal_features` lint detects unstable features enabled with
2341    /// the [`feature` attribute] that are internal to the compiler or standard
2342    /// library.
2343    ///
2344    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2345    ///
2346    /// ### Example
2347    ///
2348    /// ```rust
2349    /// #![feature(rustc_attrs)]
2350    /// ```
2351    ///
2352    /// {{produces}}
2353    ///
2354    /// ### Explanation
2355    ///
2356    /// These features are an implementation detail of the compiler and standard
2357    /// library and are not supposed to be used in user code.
2358    pub INTERNAL_FEATURES,
2359    Warn,
2360    "internal features are not supposed to be used"
2361}
2362
2363declare_lint_pass!(
2364    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
2365    IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
2366);
2367
2368impl EarlyLintPass for IncompleteInternalFeatures {
2369    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
2370        let features = cx.builder.features();
2371        let lang_features =
2372            features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
2373        let lib_features =
2374            features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
2375
2376        lang_features
2377            .chain(lib_features)
2378            .filter(|(name, _)| features.incomplete(*name) || features.internal(*name))
2379            .for_each(|(name, span)| {
2380                if features.incomplete(name) {
2381                    let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
2382                        .map(|n| BuiltinFeatureIssueNote { n });
2383                    let help =
2384                        HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
2385
2386                    cx.emit_span_lint(
2387                        INCOMPLETE_FEATURES,
2388                        span,
2389                        BuiltinIncompleteFeatures { name, note, help },
2390                    );
2391                } else {
2392                    cx.emit_span_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name });
2393                }
2394            });
2395    }
2396}
2397
2398const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
2399
2400declare_lint! {
2401    /// The `invalid_value` lint detects creating a value that is not valid,
2402    /// such as a null reference.
2403    ///
2404    /// ### Example
2405    ///
2406    /// ```rust,no_run
2407    /// # #![allow(unused)]
2408    /// unsafe {
2409    ///     let x: &'static i32 = std::mem::zeroed();
2410    /// }
2411    /// ```
2412    ///
2413    /// {{produces}}
2414    ///
2415    /// ### Explanation
2416    ///
2417    /// In some situations the compiler can detect that the code is creating
2418    /// an invalid value, which should be avoided.
2419    ///
2420    /// In particular, this lint will check for improper use of
2421    /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2422    /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2423    /// lint should provide extra information to indicate what the problem is
2424    /// and a possible solution.
2425    ///
2426    /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2427    /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2428    /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2429    /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2430    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2431    pub INVALID_VALUE,
2432    Warn,
2433    "an invalid value is being created (such as a null reference)"
2434}
2435
2436declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2437
2438/// Information about why a type cannot be initialized this way.
2439pub struct InitError {
2440    pub(crate) message: String,
2441    /// Spans from struct fields and similar that can be obtained from just the type.
2442    pub(crate) span: Option<Span>,
2443    /// Used to report a trace through adts.
2444    pub(crate) nested: Option<Box<InitError>>,
2445}
2446impl InitError {
2447    fn spanned(self, span: Span) -> InitError {
2448        Self { span: Some(span), ..self }
2449    }
2450
2451    fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
2452        assert!(self.nested.is_none());
2453        Self { nested: nested.into().map(Box::new), ..self }
2454    }
2455}
2456
2457impl<'a> From<&'a str> for InitError {
2458    fn from(s: &'a str) -> Self {
2459        s.to_owned().into()
2460    }
2461}
2462impl From<String> for InitError {
2463    fn from(message: String) -> Self {
2464        Self { message, span: None, nested: None }
2465    }
2466}
2467
2468impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2469    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2470        #[derive(Debug, Copy, Clone, PartialEq)]
2471        enum InitKind {
2472            Zeroed,
2473            Uninit,
2474        }
2475
2476        /// Test if this constant is all-0.
2477        fn is_zero(expr: &hir::Expr<'_>) -> bool {
2478            use hir::ExprKind::*;
2479            use rustc_ast::LitKind::*;
2480            match &expr.kind {
2481                Lit(lit) => {
2482                    if let Int(i, _) = lit.node {
2483                        i == 0
2484                    } else {
2485                        false
2486                    }
2487                }
2488                Tup(tup) => tup.iter().all(is_zero),
2489                _ => false,
2490            }
2491        }
2492
2493        /// Determine if this expression is a "dangerous initialization".
2494        fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
2495            if let hir::ExprKind::Call(path_expr, args) = expr.kind {
2496                // Find calls to `mem::{uninitialized,zeroed}` methods.
2497                if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2498                    let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2499                    match cx.tcx.get_diagnostic_name(def_id) {
2500                        Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2501                        Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2502                        Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2503                        _ => {}
2504                    }
2505                }
2506            } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
2507                // Find problematic calls to `MaybeUninit::assume_init`.
2508                let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
2509                if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2510                    // This is a call to *some* method named `assume_init`.
2511                    // See if the `self` parameter is one of the dangerous constructors.
2512                    if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
2513                        if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2514                            let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2515                            match cx.tcx.get_diagnostic_name(def_id) {
2516                                Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2517                                Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2518                                _ => {}
2519                            }
2520                        }
2521                    }
2522                }
2523            }
2524
2525            None
2526        }
2527
2528        fn variant_find_init_error<'tcx>(
2529            cx: &LateContext<'tcx>,
2530            ty: Ty<'tcx>,
2531            variant: &VariantDef,
2532            args: ty::GenericArgsRef<'tcx>,
2533            descr: &str,
2534            init: InitKind,
2535        ) -> Option<InitError> {
2536            let mut field_err = variant.fields.iter().find_map(|field| {
2537                ty_find_init_error(cx, field.ty(cx.tcx, args), init).map(|mut err| {
2538                    if !field.did.is_local() {
2539                        err
2540                    } else if err.span.is_none() {
2541                        err.span = Some(cx.tcx.def_span(field.did));
2542                        write!(&mut err.message, " (in this {descr})").unwrap();
2543                        err
2544                    } else {
2545                        InitError::from(format!("in this {descr}"))
2546                            .spanned(cx.tcx.def_span(field.did))
2547                            .nested(err)
2548                    }
2549                })
2550            });
2551
2552            // Check if this ADT has a constrained layout (like `NonNull` and friends).
2553            if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) {
2554                if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
2555                    &layout.backend_repr
2556                {
2557                    let range = scalar.valid_range(cx);
2558                    let msg = if !range.contains(0) {
2559                        "must be non-null"
2560                    } else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
2561                        // Prefer reporting on the fields over the entire struct for uninit,
2562                        // as the information bubbles out and it may be unclear why the type can't
2563                        // be null from just its outside signature.
2564
2565                        "must be initialized inside its custom valid range"
2566                    } else {
2567                        return field_err;
2568                    };
2569                    if let Some(field_err) = &mut field_err {
2570                        // Most of the time, if the field error is the same as the struct error,
2571                        // the struct error only happens because of the field error.
2572                        if field_err.message.contains(msg) {
2573                            field_err.message = format!("because {}", field_err.message);
2574                        }
2575                    }
2576                    return Some(InitError::from(format!("`{ty}` {msg}")).nested(field_err));
2577                }
2578            }
2579            field_err
2580        }
2581
2582        /// Return `Some` only if we are sure this type does *not*
2583        /// allow zero initialization.
2584        fn ty_find_init_error<'tcx>(
2585            cx: &LateContext<'tcx>,
2586            ty: Ty<'tcx>,
2587            init: InitKind,
2588        ) -> Option<InitError> {
2589            let ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty);
2590
2591            match ty.kind() {
2592                // Primitive types that don't like 0 as a value.
2593                ty::Ref(..) => Some("references must be non-null".into()),
2594                ty::Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()),
2595                ty::FnPtr(..) => Some("function pointers must be non-null".into()),
2596                ty::Never => Some("the `!` type has no valid value".into()),
2597                ty::RawPtr(ty, _) if matches!(ty.kind(), ty::Dynamic(..)) =>
2598                // raw ptr to dyn Trait
2599                {
2600                    Some("the vtable of a wide raw pointer must be non-null".into())
2601                }
2602                // Primitive types with other constraints.
2603                ty::Bool if init == InitKind::Uninit => {
2604                    Some("booleans must be either `true` or `false`".into())
2605                }
2606                ty::Char if init == InitKind::Uninit => {
2607                    Some("characters must be a valid Unicode codepoint".into())
2608                }
2609                ty::Int(_) | ty::Uint(_) if init == InitKind::Uninit => {
2610                    Some("integers must be initialized".into())
2611                }
2612                ty::Float(_) if init == InitKind::Uninit => {
2613                    Some("floats must be initialized".into())
2614                }
2615                ty::RawPtr(_, _) if init == InitKind::Uninit => {
2616                    Some("raw pointers must be initialized".into())
2617                }
2618                // Recurse and checks for some compound types. (but not unions)
2619                ty::Adt(adt_def, args) if !adt_def.is_union() => {
2620                    // Handle structs.
2621                    if adt_def.is_struct() {
2622                        return variant_find_init_error(
2623                            cx,
2624                            ty,
2625                            adt_def.non_enum_variant(),
2626                            args,
2627                            "struct field",
2628                            init,
2629                        );
2630                    }
2631                    // And now, enums.
2632                    let span = cx.tcx.def_span(adt_def.did());
2633                    let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
2634                        let definitely_inhabited = match variant
2635                            .inhabited_predicate(cx.tcx, *adt_def)
2636                            .instantiate(cx.tcx, args)
2637                            .apply_any_module(cx.tcx, cx.typing_env())
2638                        {
2639                            // Entirely skip uninhabited variants.
2640                            Some(false) => return None,
2641                            // Forward the others, but remember which ones are definitely inhabited.
2642                            Some(true) => true,
2643                            None => false,
2644                        };
2645                        Some((variant, definitely_inhabited))
2646                    });
2647                    let Some(first_variant) = potential_variants.next() else {
2648                        return Some(
2649                            InitError::from("enums with no inhabited variants have no valid value")
2650                                .spanned(span),
2651                        );
2652                    };
2653                    // So we have at least one potentially inhabited variant. Might we have two?
2654                    let Some(second_variant) = potential_variants.next() else {
2655                        // There is only one potentially inhabited variant. So we can recursively
2656                        // check that variant!
2657                        return variant_find_init_error(
2658                            cx,
2659                            ty,
2660                            first_variant.0,
2661                            args,
2662                            "field of the only potentially inhabited enum variant",
2663                            init,
2664                        );
2665                    };
2666                    // So we have at least two potentially inhabited variants. If we can prove that
2667                    // we have at least two *definitely* inhabited variants, then we have a tag and
2668                    // hence leaving this uninit is definitely disallowed. (Leaving it zeroed could
2669                    // be okay, depending on which variant is encoded as zero tag.)
2670                    if init == InitKind::Uninit {
2671                        let definitely_inhabited = (first_variant.1 as usize)
2672                            + (second_variant.1 as usize)
2673                            + potential_variants
2674                                .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
2675                                .count();
2676                        if definitely_inhabited > 1 {
2677                            return Some(InitError::from(
2678                                "enums with multiple inhabited variants have to be initialized to a variant",
2679                            ).spanned(span));
2680                        }
2681                    }
2682                    // We couldn't find anything wrong here.
2683                    None
2684                }
2685                ty::Tuple(..) => {
2686                    // Proceed recursively, check all fields.
2687                    ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2688                }
2689                ty::Array(ty, len) => {
2690                    if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) {
2691                        // Array length known at array non-empty -- recurse.
2692                        ty_find_init_error(cx, *ty, init)
2693                    } else {
2694                        // Empty array or size unknown.
2695                        None
2696                    }
2697                }
2698                // Conservative fallback.
2699                _ => None,
2700            }
2701        }
2702
2703        if let Some(init) = is_dangerous_init(cx, expr) {
2704            // This conjures an instance of a type out of nothing,
2705            // using zeroed or uninitialized memory.
2706            // We are extremely conservative with what we warn about.
2707            let conjured_ty = cx.typeck_results().expr_ty(expr);
2708            if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
2709                let msg = match init {
2710                    InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
2711                    InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
2712                };
2713                let sub = BuiltinUnpermittedTypeInitSub { err };
2714                cx.emit_span_lint(
2715                    INVALID_VALUE,
2716                    expr.span,
2717                    BuiltinUnpermittedTypeInit {
2718                        msg,
2719                        ty: conjured_ty,
2720                        label: expr.span,
2721                        sub,
2722                        tcx: cx.tcx,
2723                    },
2724                );
2725            }
2726        }
2727    }
2728}
2729
2730declare_lint! {
2731    /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
2732    /// which causes [undefined behavior].
2733    ///
2734    /// ### Example
2735    ///
2736    /// ```rust,no_run
2737    /// # #![allow(unused)]
2738    /// use std::ptr;
2739    /// unsafe {
2740    ///     let x = &*ptr::null::<i32>();
2741    ///     let x = ptr::addr_of!(*ptr::null::<i32>());
2742    ///     let x = *(0 as *const i32);
2743    /// }
2744    /// ```
2745    ///
2746    /// {{produces}}
2747    ///
2748    /// ### Explanation
2749    ///
2750    /// Dereferencing a null pointer causes [undefined behavior] if it is accessed
2751    /// (loaded from or stored to).
2752    ///
2753    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2754    pub DEREF_NULLPTR,
2755    Warn,
2756    "detects when an null pointer is dereferenced"
2757}
2758
2759declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
2760
2761impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
2762    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2763        /// test if expression is a null ptr
2764        fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
2765            match &expr.kind {
2766                hir::ExprKind::Cast(expr, ty) => {
2767                    if let hir::TyKind::Ptr(_) = ty.kind {
2768                        return is_zero(expr) || is_null_ptr(cx, expr);
2769                    }
2770                }
2771                // check for call to `core::ptr::null` or `core::ptr::null_mut`
2772                hir::ExprKind::Call(path, _) => {
2773                    if let hir::ExprKind::Path(ref qpath) = path.kind {
2774                        if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
2775                            return matches!(
2776                                cx.tcx.get_diagnostic_name(def_id),
2777                                Some(sym::ptr_null | sym::ptr_null_mut)
2778                            );
2779                        }
2780                    }
2781                }
2782                _ => {}
2783            }
2784            false
2785        }
2786
2787        /// test if expression is the literal `0`
2788        fn is_zero(expr: &hir::Expr<'_>) -> bool {
2789            match &expr.kind {
2790                hir::ExprKind::Lit(lit) => {
2791                    if let LitKind::Int(a, _) = lit.node {
2792                        return a == 0;
2793                    }
2794                }
2795                _ => {}
2796            }
2797            false
2798        }
2799
2800        if let hir::ExprKind::Unary(hir::UnOp::Deref, expr_deref) = expr.kind
2801            && is_null_ptr(cx, expr_deref)
2802        {
2803            if let hir::Node::Expr(hir::Expr {
2804                kind: hir::ExprKind::AddrOf(hir::BorrowKind::Raw, ..),
2805                ..
2806            }) = cx.tcx.parent_hir_node(expr.hir_id)
2807            {
2808                // `&raw *NULL` is ok.
2809            } else {
2810                cx.emit_span_lint(
2811                    DEREF_NULLPTR,
2812                    expr.span,
2813                    BuiltinDerefNullptr { label: expr.span },
2814                );
2815            }
2816        }
2817    }
2818}
2819
2820declare_lint! {
2821    /// The `named_asm_labels` lint detects the use of named labels in the
2822    /// inline `asm!` macro.
2823    ///
2824    /// ### Example
2825    ///
2826    /// ```rust,compile_fail
2827    /// # #![feature(asm_experimental_arch)]
2828    /// use std::arch::asm;
2829    ///
2830    /// fn main() {
2831    ///     unsafe {
2832    ///         asm!("foo: bar");
2833    ///     }
2834    /// }
2835    /// ```
2836    ///
2837    /// {{produces}}
2838    ///
2839    /// ### Explanation
2840    ///
2841    /// LLVM is allowed to duplicate inline assembly blocks for any
2842    /// reason, for example when it is in a function that gets inlined. Because
2843    /// of this, GNU assembler [local labels] *must* be used instead of labels
2844    /// with a name. Using named labels might cause assembler or linker errors.
2845    ///
2846    /// See the explanation in [Rust By Example] for more details.
2847    ///
2848    /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
2849    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2850    pub NAMED_ASM_LABELS,
2851    Deny,
2852    "named labels in inline assembly",
2853}
2854
2855declare_lint! {
2856    /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary
2857    /// digits in the inline `asm!` macro.
2858    ///
2859    /// ### Example
2860    ///
2861    /// ```rust,ignore (fails on non-x86_64)
2862    /// #![cfg(target_arch = "x86_64")]
2863    ///
2864    /// use std::arch::asm;
2865    ///
2866    /// fn main() {
2867    ///     unsafe {
2868    ///         asm!("0: jmp 0b");
2869    ///     }
2870    /// }
2871    /// ```
2872    ///
2873    /// This will produce:
2874    ///
2875    /// ```text
2876    /// error: avoid using labels containing only the digits `0` and `1` in inline assembly
2877    ///  --> <source>:7:15
2878    ///   |
2879    /// 7 |         asm!("0: jmp 0b");
2880    ///   |               ^ use a different label that doesn't start with `0` or `1`
2881    ///   |
2882    ///   = help: start numbering with `2` instead
2883    ///   = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86
2884    ///   = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information
2885    ///   = note: `#[deny(binary_asm_labels)]` on by default
2886    /// ```
2887    ///
2888    /// ### Explanation
2889    ///
2890    /// An [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary
2891    /// literal instead of a reference to the previous local label `0`. To work around this bug,
2892    /// don't use labels that could be confused with a binary literal.
2893    ///
2894    /// This behavior is platform-specific to x86 and x86-64.
2895    ///
2896    /// See the explanation in [Rust By Example] for more details.
2897    ///
2898    /// [LLVM bug]: https://github.com/llvm/llvm-project/issues/99547
2899    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2900    pub BINARY_ASM_LABELS,
2901    Deny,
2902    "labels in inline assembly containing only 0 or 1 digits",
2903}
2904
2905declare_lint_pass!(AsmLabels => [NAMED_ASM_LABELS, BINARY_ASM_LABELS]);
2906
2907#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2908enum AsmLabelKind {
2909    Named,
2910    FormatArg,
2911    Binary,
2912}
2913
2914impl<'tcx> LateLintPass<'tcx> for AsmLabels {
2915    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
2916        if let hir::Expr {
2917            kind:
2918                hir::ExprKind::InlineAsm(hir::InlineAsm {
2919                    asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
2920                    template_strs,
2921                    options,
2922                    ..
2923                }),
2924            ..
2925        } = expr
2926        {
2927            // asm with `options(raw)` does not do replacement with `{` and `}`.
2928            let raw = options.contains(InlineAsmOptions::RAW);
2929
2930            for (template_sym, template_snippet, template_span) in template_strs.iter() {
2931                let template_str = template_sym.as_str();
2932                let find_label_span = |needle: &str| -> Option<Span> {
2933                    if let Some(template_snippet) = template_snippet {
2934                        let snippet = template_snippet.as_str();
2935                        if let Some(pos) = snippet.find(needle) {
2936                            let end = pos
2937                                + snippet[pos..]
2938                                    .find(|c| c == ':')
2939                                    .unwrap_or(snippet[pos..].len() - 1);
2940                            let inner = InnerSpan::new(pos, end);
2941                            return Some(template_span.from_inner(inner));
2942                        }
2943                    }
2944
2945                    None
2946                };
2947
2948                // diagnostics are emitted per-template, so this is created here as opposed to the outer loop
2949                let mut spans = Vec::new();
2950
2951                // A semicolon might not actually be specified as a separator for all targets, but
2952                // it seems like LLVM accepts it always.
2953                let statements = template_str.split(|c| matches!(c, '\n' | ';'));
2954                for statement in statements {
2955                    // If there's a comment, trim it from the statement
2956                    let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
2957
2958                    // In this loop, if there is ever a non-label, no labels can come after it.
2959                    let mut start_idx = 0;
2960                    'label_loop: for (idx, _) in statement.match_indices(':') {
2961                        let possible_label = statement[start_idx..idx].trim();
2962                        let mut chars = possible_label.chars();
2963
2964                        let Some(start) = chars.next() else {
2965                            // Empty string means a leading ':' in this section, which is not a
2966                            // label.
2967                            break 'label_loop;
2968                        };
2969
2970                        // Whether a { bracket has been seen and its } hasn't been found yet.
2971                        let mut in_bracket = false;
2972                        let mut label_kind = AsmLabelKind::Named;
2973
2974                        // A label can also start with a format arg, if it's not a raw asm block.
2975                        if !raw && start == '{' {
2976                            in_bracket = true;
2977                            label_kind = AsmLabelKind::FormatArg;
2978                        } else if matches!(start, '0' | '1') {
2979                            // Binary labels have only the characters `0` or `1`.
2980                            label_kind = AsmLabelKind::Binary;
2981                        } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) {
2982                            // Named labels start with ASCII letters, `.` or `_`.
2983                            // anything else is not a label
2984                            break 'label_loop;
2985                        }
2986
2987                        for c in chars {
2988                            // Inside a template format arg, any character is permitted for the
2989                            // puproses of label detection because we assume that it can be
2990                            // replaced with some other valid label string later. `options(raw)`
2991                            // asm blocks cannot have format args, so they are excluded from this
2992                            // special case.
2993                            if !raw && in_bracket {
2994                                if c == '{' {
2995                                    // Nested brackets are not allowed in format args, this cannot
2996                                    // be a label.
2997                                    break 'label_loop;
2998                                }
2999
3000                                if c == '}' {
3001                                    // The end of the format arg.
3002                                    in_bracket = false;
3003                                }
3004                            } else if !raw && c == '{' {
3005                                // Start of a format arg.
3006                                in_bracket = true;
3007                                label_kind = AsmLabelKind::FormatArg;
3008                            } else {
3009                                let can_continue = match label_kind {
3010                                    // Format arg labels are considered to be named labels for the purposes
3011                                    // of continuing outside of their {} pair.
3012                                    AsmLabelKind::Named | AsmLabelKind::FormatArg => {
3013                                        c.is_ascii_alphanumeric() || matches!(c, '_' | '$')
3014                                    }
3015                                    AsmLabelKind::Binary => matches!(c, '0' | '1'),
3016                                };
3017
3018                                if !can_continue {
3019                                    // The potential label had an invalid character inside it, it
3020                                    // cannot be a label.
3021                                    break 'label_loop;
3022                                }
3023                            }
3024                        }
3025
3026                        // If all characters passed the label checks, this is a label.
3027                        spans.push((find_label_span(possible_label), label_kind));
3028                        start_idx = idx + 1;
3029                    }
3030                }
3031
3032                for (span, label_kind) in spans {
3033                    let missing_precise_span = span.is_none();
3034                    let span = span.unwrap_or(*template_span);
3035                    match label_kind {
3036                        AsmLabelKind::Named => {
3037                            cx.emit_span_lint(
3038                                NAMED_ASM_LABELS,
3039                                span,
3040                                InvalidAsmLabel::Named { missing_precise_span },
3041                            );
3042                        }
3043                        AsmLabelKind::FormatArg => {
3044                            cx.emit_span_lint(
3045                                NAMED_ASM_LABELS,
3046                                span,
3047                                InvalidAsmLabel::FormatArg { missing_precise_span },
3048                            );
3049                        }
3050                        // the binary asm issue only occurs when using intel syntax on x86 targets
3051                        AsmLabelKind::Binary
3052                            if !options.contains(InlineAsmOptions::ATT_SYNTAX)
3053                                && matches!(
3054                                    cx.tcx.sess.asm_arch,
3055                                    Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None
3056                                ) =>
3057                        {
3058                            cx.emit_span_lint(
3059                                BINARY_ASM_LABELS,
3060                                span,
3061                                InvalidAsmLabel::Binary { missing_precise_span, span },
3062                            )
3063                        }
3064                        // No lint on anything other than x86
3065                        AsmLabelKind::Binary => (),
3066                    };
3067                }
3068            }
3069        }
3070    }
3071}
3072
3073declare_lint! {
3074    /// The `special_module_name` lint detects module
3075    /// declarations for files that have a special meaning.
3076    ///
3077    /// ### Example
3078    ///
3079    /// ```rust,compile_fail
3080    /// mod lib;
3081    ///
3082    /// fn main() {
3083    ///     lib::run();
3084    /// }
3085    /// ```
3086    ///
3087    /// {{produces}}
3088    ///
3089    /// ### Explanation
3090    ///
3091    /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
3092    /// library or binary crate, so declaring them as modules
3093    /// will lead to miscompilation of the crate unless configured
3094    /// explicitly.
3095    ///
3096    /// To access a library from a binary target within the same crate,
3097    /// use `your_crate_name::` as the path instead of `lib::`:
3098    ///
3099    /// ```rust,compile_fail
3100    /// // bar/src/lib.rs
3101    /// fn run() {
3102    ///     // ...
3103    /// }
3104    ///
3105    /// // bar/src/main.rs
3106    /// fn main() {
3107    ///     bar::run();
3108    /// }
3109    /// ```
3110    ///
3111    /// Binary targets cannot be used as libraries and so declaring
3112    /// one as a module is not allowed.
3113    pub SPECIAL_MODULE_NAME,
3114    Warn,
3115    "module declarations for files with a special meaning",
3116}
3117
3118declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
3119
3120impl EarlyLintPass for SpecialModuleName {
3121    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
3122        for item in &krate.items {
3123            if let ast::ItemKind::Mod(
3124                _,
3125                ident,
3126                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
3127            ) = item.kind
3128            {
3129                if item.attrs.iter().any(|a| a.has_name(sym::path)) {
3130                    continue;
3131                }
3132
3133                match ident.name.as_str() {
3134                    "lib" => cx.emit_span_lint(
3135                        SPECIAL_MODULE_NAME,
3136                        item.span,
3137                        BuiltinSpecialModuleNameUsed::Lib,
3138                    ),
3139                    "main" => cx.emit_span_lint(
3140                        SPECIAL_MODULE_NAME,
3141                        item.span,
3142                        BuiltinSpecialModuleNameUsed::Main,
3143                    ),
3144                    _ => continue,
3145                }
3146            }
3147        }
3148    }
3149}