compiler/rustc_lint/src/builtin.rs RUST 3,195 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,195.
1//! Lints in the Rust compiler.2//!3//! This contains lints which can feasibly be implemented as their own4//! AST visitor. Also see `rustc_session::lint::builtin`, which contains the5//! 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 the11//! [`crate::early_lint_methods!`] invocation in `lib.rs`.12//!13//! If you define a new [`LateLintPass`], you will also need to add it to the14//! [`crate::late_lint_methods!`] invocation in `lib.rs`.1516use std::fmt::Write;1718use 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_attr_parsing::AttributeParser;25use rustc_errors::{Applicability, Diagnostic, msg};26use rustc_feature::GateIssue;27use rustc_hir::attrs::{AttributeKind, DocAttribute};28use rustc_hir::def::{DefKind, Res};29use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};30use rustc_hir::intravisit::FnKind as HirFnKind;31use rustc_hir::{self as hir, Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr};32use rustc_middle::bug;33use rustc_middle::ty::layout::LayoutOf;34use rustc_middle::ty::print::with_no_trimmed_paths;35use rustc_middle::ty::{36    self, AssocContainer, Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast, VariantDef,37};38// hardwired lints from rustc_lint_defs39pub use rustc_session::lint::builtin::*;40use rustc_session::lint::fcw;41use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};42use rustc_span::edition::Edition;43use rustc_span::{DUMMY_SP, Ident, InnerSpan, Span, Spanned, Symbol, kw, sym};44use rustc_target::asm::InlineAsmArch;45use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};46use rustc_trait_selection::traits;47use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;48use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;4950use crate::diagnostics::BuiltinEllipsisInclusiveRangePatterns;51use crate::lints::{52    BuiltinAnonymousParams, BuiltinConstNoMangle, 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, EqInternalMethodImplemented, InvalidAsmLabel,62};63use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};6465declare_lint! {66    /// The `while_true` lint detects `while true { }`.67    ///68    /// ### Example69    ///70    /// ```rust,no_run71    /// while true {72    ///73    /// }74    /// ```75    ///76    /// {{produces}}77    ///78    /// ### Explanation79    ///80    /// `while true` should be replaced with `loop`. A `loop` expression is81    /// the preferred way to write an infinite loop because it more directly82    /// expresses the intent of the loop.83    WHILE_TRUE,84    Warn,85    "suggest using `loop { }` instead of `while true { }`"86}8788declare_lint_pass!(WhileTrue => [WHILE_TRUE]);8990impl EarlyLintPass for WhileTrue {91    #[inline]92    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {93        if let ast::ExprKind::While(cond, _, label) = &e.kind94            && let ast::ExprKind::Lit(token_lit) = cond.peel_parens().kind95            && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit96            && !cond.span.from_expansion()97        {98            let condition_span = e.span.with_hi(cond.span.hi());99            let replace = format!(100                "{}loop",101                label.map_or_else(String::new, |label| format!("{}: ", label.ident,))102            );103            cx.emit_span_lint(104                WHILE_TRUE,105                condition_span,106                BuiltinWhileTrue { suggestion: condition_span, replace },107            );108        }109    }110}111112declare_lint! {113    /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`114    /// instead of `Struct { x }` in a pattern.115    ///116    /// ### Example117    ///118    /// ```rust119    /// struct Point {120    ///     x: i32,121    ///     y: i32,122    /// }123    ///124    ///125    /// fn main() {126    ///     let p = Point {127    ///         x: 5,128    ///         y: 5,129    ///     };130    ///131    ///     match p {132    ///         Point { x: x, y: y } => (),133    ///     }134    /// }135    /// ```136    ///137    /// {{produces}}138    ///139    /// ### Explanation140    ///141    /// The preferred style is to avoid the repetition of specifying both the142    /// field name and the binding name if both identifiers are the same.143    NON_SHORTHAND_FIELD_PATTERNS,144    Warn,145    "using `Struct { x: x }` instead of `Struct { x }` in a pattern"146}147148declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);149150impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {151    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {152        // The result shouldn't be tainted, otherwise it will cause ICE.153        if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind154            && cx.typeck_results().tainted_by_errors.is_none()155        {156            let variant = cx157                .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 authors168                    // shouldn't have to worry about this kind of style issue169                    // (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}191192declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);193194impl UnsafeCode {195    fn report_unsafe(196        &self,197        cx: &EarlyContext<'_>,198        span: Span,199        decorate: impl for<'a> Diagnostic<'a, ()>,200    ) {201        // This comes from a macro that has `#[allow_internal_unsafe]`.202        if span.allows_unsafe() {203            return;204        }205206        cx.emit_span_lint(UNSAFE_CODE, span, decorate);207    }208}209210impl EarlyLintPass for UnsafeCode {211    #[inline]212    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {213        if let ast::ExprKind::Block(ref blk, _) = e.kind {214            // Don't warn about generated blocks; that'll just pollute the output.215            if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {216                self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock);217            }218        }219    }220221    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {222        match it.kind {223            ast::ItemKind::Trait(ast::Trait { safety: ast::Safety::Unsafe(_), .. }) => {224                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);225            }226227            ast::ItemKind::Impl(ast::Impl {228                of_trait: Some(ast::TraitImplHeader { safety: ast::Safety::Unsafe(_), .. }),229                ..230            }) => {231                self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);232            }233234            ast::ItemKind::GlobalAsm(..) => {235                self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm);236            }237238            ast::ItemKind::ForeignMod(ForeignMod { safety, .. }) => {239                if let Safety::Unsafe(_) = safety {240                    self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeExternBlock);241                }242            }243244            ast::ItemKind::MacroDef(..) => {245                if let Some(hir::Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span))) =246                    AttributeParser::parse_limited(247                        cx.builder.sess(),248                        &it.attrs,249                        &[sym::allow_internal_unsafe],250                    )251                {252                    self.report_unsafe(cx, span, BuiltinUnsafe::AllowInternalUnsafe);253                }254            }255256            _ => {}257        }258    }259260    fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {261        if let FnKind::Fn(262            ctxt,263            _,264            ast::Fn {265                sig: ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },266                body,267                ..268            },269        ) = fk270        {271            let decorator = match ctxt {272                FnCtxt::Foreign => return,273                FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn,274                FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod,275                FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod,276            };277            self.report_unsafe(cx, span, decorator);278        }279    }280}281282declare_lint! {283    /// The `missing_docs` lint detects missing documentation for public items.284    ///285    /// ### Example286    ///287    /// ```rust,compile_fail288    /// #![deny(missing_docs)]289    /// pub fn foo() {}290    /// ```291    ///292    /// {{produces}}293    ///294    /// ### Explanation295    ///296    /// This lint is intended to ensure that a library is well-documented.297    /// Items without documentation can be difficult for users to understand298    /// how to use properly.299    ///300    /// This lint is "allow" by default because it can be noisy, and not all301    /// projects may want to enforce everything to be documented.302    pub MISSING_DOCS,303    Allow,304    "detects missing documentation for public members",305    report_in_external_macro306}307308#[derive(Default)]309pub struct MissingDoc;310311impl_lint_pass!(MissingDoc => [MISSING_DOCS]);312313fn has_doc(attr: &hir::Attribute) -> bool {314    if matches!(attr, hir::Attribute::Parsed(AttributeKind::DocComment { .. })) {315        return true;316    }317318    if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr319        && matches!(d.as_ref(), DocAttribute { hidden: Some(..), .. })320    {321        return true;322    }323324    false325}326327impl MissingDoc {328    fn check_missing_docs_attrs(329        &self,330        cx: &LateContext<'_>,331        def_id: LocalDefId,332        article: &'static str,333        desc: &'static str,334    ) {335        // Only check publicly-visible items, using the result from the privacy pass.336        // It's an option so the crate root can also use this function (it doesn't337        // have a `NodeId`).338        if def_id != CRATE_DEF_ID && !cx.effective_visibilities.is_exported(def_id) {339            return;340        }341342        let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id));343        let has_doc = attrs.iter().any(has_doc);344        if !has_doc {345            cx.emit_span_lint(346                MISSING_DOCS,347                cx.tcx.def_span(def_id),348                BuiltinMissingDoc { article, desc },349            );350        }351    }352}353354impl<'tcx> LateLintPass<'tcx> for MissingDoc {355    fn check_crate(&mut self, cx: &LateContext<'_>) {356        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");357    }358359    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {360        // Previously the Impl and Use types have been excluded from missing docs,361        // so we will continue to exclude them for compatibility.362        //363        // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.364        if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) =365            it.kind366        {367            return;368        }369370        let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());371        self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);372    }373374    fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {375        let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());376377        self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);378    }379380    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {381        let container = cx.tcx.associated_item(impl_item.owner_id.def_id).container;382383        match container {384            // If the method is an impl for a trait, don't doc.385            AssocContainer::TraitImpl(_) => return,386            AssocContainer::Trait => {}387            // If the method is an impl for an item with docs_hidden, don't doc.388            AssocContainer::InherentImpl => {389                let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id());390                let impl_ty = cx.tcx.type_of(parent).instantiate_identity().skip_norm_wip();391                let outerdef = match impl_ty.kind() {392                    ty::Adt(def, _) => Some(def.did()),393                    ty::Foreign(def_id) => Some(*def_id),394                    _ => None,395                };396                let is_hidden = match outerdef {397                    Some(id) => cx.tcx.is_doc_hidden(id),398                    None => false,399                };400                if is_hidden {401                    return;402                }403            }404        }405406        let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());407        self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);408    }409410    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {411        let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());412        self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);413    }414415    fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {416        if !sf.is_positional() {417            self.check_missing_docs_attrs(cx, sf.def_id, "a", "struct field")418        }419    }420421    fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {422        self.check_missing_docs_attrs(cx, v.def_id, "a", "variant");423    }424}425426declare_lint! {427    /// The `missing_copy_implementations` lint detects potentially-forgotten428    /// implementations of [`Copy`] for public types.429    ///430    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html431    ///432    /// ### Example433    ///434    /// ```rust,compile_fail435    /// #![deny(missing_copy_implementations)]436    /// pub struct Foo {437    ///     pub field: i32438    /// }439    /// # fn main() {}440    /// ```441    ///442    /// {{produces}}443    ///444    /// ### Explanation445    ///446    /// Historically (before 1.0), types were automatically marked as `Copy`447    /// if possible. This was changed so that it required an explicit opt-in448    /// by implementing the `Copy` trait. As part of this change, a lint was449    /// added to alert if a copyable type was not marked `Copy`.450    ///451    /// This lint is "allow" by default because this code isn't bad; it is452    /// common to write newtypes like this specifically so that a `Copy` type453    /// is no longer `Copy`. `Copy` types can result in unintended copies of454    /// large data which can impact performance.455    pub MISSING_COPY_IMPLEMENTATIONS,456    Allow,457    "detects potentially-forgotten implementations of `Copy`"458}459460declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);461462impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {463    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {464        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {465            return;466        }467        let (def, ty) = match item.kind {468            hir::ItemKind::Struct(_, generics, _) => {469                if !generics.params.is_empty() {470                    return;471                }472                let def = cx.tcx.adt_def(item.owner_id);473                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))474            }475            hir::ItemKind::Union(_, generics, _) => {476                if !generics.params.is_empty() {477                    return;478                }479                let def = cx.tcx.adt_def(item.owner_id);480                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))481            }482            hir::ItemKind::Enum(_, generics, _) => {483                if !generics.params.is_empty() {484                    return;485                }486                let def = cx.tcx.adt_def(item.owner_id);487                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))488            }489            _ => return,490        };491        if def.has_dtor(cx.tcx) {492            return;493        }494495        // If the type contains a raw pointer, it may represent something like a handle,496        // and recommending Copy might be a bad idea.497        for field in def.all_fields() {498            let did = field.did;499            if cx.tcx.type_of(did).instantiate_identity().skip_norm_wip().is_raw_ptr() {500                return;501            }502        }503        if cx.type_is_copy_modulo_regions(ty) {504            return;505        }506        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) {507            return;508        }509        if def.is_variant_list_non_exhaustive()510            || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive())511        {512            return;513        }514515        // We shouldn't recommend implementing `Copy` on stateful things,516        // such as iterators.517        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)518            && cx519                .tcx520                .infer_ctxt()521                .build(cx.typing_mode())522                .type_implements_trait(iter_trait, [ty], cx.param_env)523                .must_apply_modulo_regions()524        {525            return;526        }527528        // Default value of clippy::trivially_copy_pass_by_ref529        const MAX_SIZE: u64 = 256;530531        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {532            if size > MAX_SIZE {533                return;534            }535        }536537        if type_allowed_to_implement_copy(538            cx.tcx,539            cx.param_env,540            ty,541            traits::ObligationCause::misc(item.span, item.owner_id.def_id),542            hir::Safety::Safe,543        )544        .is_ok()545        {546            cx.emit_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl);547        }548    }549}550551/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.552fn type_implements_negative_copy_modulo_regions<'tcx>(553    tcx: TyCtxt<'tcx>,554    ty: Ty<'tcx>,555    typing_env: ty::TypingEnv<'tcx>,556) -> bool {557    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);558    let trait_ref =559        ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, DUMMY_SP), [ty]);560    let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };561    let obligation = traits::Obligation {562        cause: traits::ObligationCause::dummy(),563        param_env,564        recursion_depth: 0,565        predicate: pred.upcast(tcx),566    };567    infcx.predicate_must_hold_modulo_regions(&obligation)568}569570declare_lint! {571    /// The `missing_debug_implementations` lint detects missing572    /// implementations of [`fmt::Debug`] for public types.573    ///574    /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html575    ///576    /// ### Example577    ///578    /// ```rust,compile_fail579    /// #![deny(missing_debug_implementations)]580    /// pub struct Foo;581    /// # fn main() {}582    /// ```583    ///584    /// {{produces}}585    ///586    /// ### Explanation587    ///588    /// Having a `Debug` implementation on all types can assist with589    /// debugging, as it provides a convenient way to format and display a590    /// value. Using the `#[derive(Debug)]` attribute will automatically591    /// generate a typical implementation, or a custom implementation can be592    /// added by manually implementing the `Debug` trait.593    ///594    /// This lint is "allow" by default because adding `Debug` to all types can595    /// have a negative impact on compile time and code size. It also requires596    /// boilerplate to be added to every type, which can be an impediment.597    MISSING_DEBUG_IMPLEMENTATIONS,598    Allow,599    "detects missing implementations of Debug"600}601602#[derive(Default)]603pub(crate) struct MissingDebugImplementations;604605impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);606607impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {608    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {609        let def_id = item.owner_id.def_id;610        if !cx.effective_visibilities.is_reachable(def_id) {611            return;612        }613614        let is_generic = match item.kind {615            hir::ItemKind::Struct(_, generics, _)616            | hir::ItemKind::Union(_, generics, _)617            | hir::ItemKind::Enum(_, generics, _) => !generics.params.is_empty(),618            _ => return,619        };620621        let tcx = cx.tcx;622623        // Avoid listing trait impls if the trait is allowed.624        if tcx.lint_level_spec_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id()).is_allow() {625            return;626        }627628        let Some(debug) = tcx.get_diagnostic_item(sym::Debug) else { return };629630        let ty = tcx.type_of(item.owner_id);631        if tcx632            .non_blanket_impls_for_ty(debug, ty.instantiate_identity().skip_norm_wip())633            .next()634            .is_some()635        {636            return;637        }638639        let infcx = tcx.infer_ctxt().build(cx.typing_mode());640        if is_generic {641            let args = infcx.fresh_args_for_item(item.span, def_id.to_def_id());642            if infcx643                .type_implements_trait_shallow(644                    debug,645                    ty.instantiate(tcx, args).skip_norm_wip(),646                    cx.param_env,647                )648                .is_some()649            {650                return;651            }652        } else if infcx653            .type_implements_trait(debug, [ty.instantiate_identity().skip_norm_wip()], cx.param_env)654            .must_apply_modulo_regions()655        {656            return;657        }658659        cx.emit_span_lint(660            MISSING_DEBUG_IMPLEMENTATIONS,661            item.span,662            BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug },663        );664    }665}666667declare_lint! {668    /// The `anonymous_parameters` lint detects anonymous parameters in trait669    /// definitions.670    ///671    /// ### Example672    ///673    /// ```rust,edition2015,compile_fail674    /// #![deny(anonymous_parameters)]675    /// // edition 2015676    /// pub trait Foo {677    ///     fn foo(usize);678    /// }679    /// fn main() {}680    /// ```681    ///682    /// {{produces}}683    ///684    /// ### Explanation685    ///686    /// This syntax is mostly a historical accident, and can be worked around687    /// quite easily by adding an `_` pattern or a descriptive identifier:688    ///689    /// ```rust690    /// trait Foo {691    ///     fn foo(_: usize);692    /// }693    /// ```694    ///695    /// This syntax is now a hard error in the 2018 edition. In the 2015696    /// edition, this lint is "warn" by default. This lint697    /// enables the [`cargo fix`] tool with the `--edition` flag to698    /// automatically transition old code from the 2015 edition to 2018. The699    /// tool will run this lint and automatically apply the700    /// suggested fix from the compiler (which is to add `_` to each701    /// parameter). This provides a completely automated way to update old702    /// code for a new edition. See [issue #41686] for more details.703    ///704    /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686705    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html706    pub ANONYMOUS_PARAMETERS,707    Warn,708    "detects anonymous parameters",709    @future_incompatible = FutureIncompatibleInfo {710        reason: fcw!(EditionError 2018 "trait-fn-parameters"),711    };712}713714declare_lint_pass!(715    /// Checks for use of anonymous parameters (RFC 1685).716    AnonymousParameters => [ANONYMOUS_PARAMETERS]717);718719impl EarlyLintPass for AnonymousParameters {720    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {721        if cx.sess().edition() != Edition::Edition2015 {722            // This is a hard error in future editions; avoid linting and erroring723            return;724        }725        if let ast::AssocItemKind::Fn(Fn { ref sig, .. }) = it.kind {726            for arg in sig.decl.inputs.iter() {727                if let ast::PatKind::Missing = arg.pat.kind {728                    let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);729730                    let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {731                        (snip.as_str(), Applicability::MachineApplicable)732                    } else {733                        ("<type>", Applicability::HasPlaceholders)734                    };735                    cx.emit_span_lint(736                        ANONYMOUS_PARAMETERS,737                        arg.pat.span,738                        BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },739                    );740                }741            }742        }743    }744}745746fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {747    use rustc_ast::token::CommentKind;748749    let mut attrs = attrs.iter().peekable();750751    // Accumulate a single span for sugared doc comments.752    let mut sugared_span: Option<Span> = None;753754    while let Some(attr) = attrs.next() {755        let (is_doc_comment, is_doc_attribute) = match &attr.kind {756            AttrKind::DocComment(..) => (true, false),757            AttrKind::Normal(normal) if normal.item.path == sym::doc => (true, true),758            _ => (false, false),759        };760        if is_doc_comment {761            sugared_span =762                Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));763        }764765        if !is_doc_attribute && attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) {766            continue;767        }768769        let span = sugared_span.take().unwrap_or(attr.span);770771        if is_doc_comment || is_doc_attribute {772            let sub = match attr.kind {773                AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {774                    BuiltinUnusedDocCommentSub::PlainHelp775                }776                AttrKind::DocComment(CommentKind::Block, _) => {777                    BuiltinUnusedDocCommentSub::BlockHelp778                }779            };780            cx.emit_span_lint(781                UNUSED_DOC_COMMENTS,782                span,783                BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub },784            );785        }786    }787}788789impl EarlyLintPass for UnusedDocComment {790    fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {791        let kind = match stmt.kind {792            ast::StmtKind::Let(..) => "statements",793            // Disabled pending discussion in #78306794            ast::StmtKind::Item(..) => return,795            // expressions will be reported by `check_expr`.796            ast::StmtKind::Empty797            | ast::StmtKind::Semi(_)798            | ast::StmtKind::Expr(_)799            | ast::StmtKind::MacCall(_) => return,800        };801802        warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());803    }804805    fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {806        if let Some(body) = &arm.body {807            let arm_span = arm.pat.span.with_hi(body.span.hi());808            warn_if_doc(cx, arm_span, "match arms", &arm.attrs);809        }810    }811812    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {813        if let ast::PatKind::Struct(_, _, fields, _) = &pat.kind {814            for field in fields {815                warn_if_doc(cx, field.span, "pattern fields", &field.attrs);816            }817        }818    }819820    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {821        warn_if_doc(cx, expr.span, "expressions", &expr.attrs);822823        if let ExprKind::Struct(s) = &expr.kind {824            for field in &s.fields {825                warn_if_doc(cx, field.span, "expression fields", &field.attrs);826            }827        }828    }829830    fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {831        warn_if_doc(cx, param.ident.span, "generic parameters", &param.attrs);832    }833834    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {835        warn_if_doc(cx, block.span, "blocks", block.attrs());836    }837838    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {839        if let ast::ItemKind::ForeignMod(_) = item.kind {840            warn_if_doc(cx, item.span, "extern blocks", &item.attrs);841        }842    }843}844845declare_lint! {846    /// The `no_mangle_const_items` lint detects any `const` items with the847    /// [`no_mangle` attribute].848    ///849    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute850    ///851    /// ### Example852    ///853    /// ```rust,compile_fail,edition2021854    /// #[no_mangle]855    /// const FOO: i32 = 5;856    /// ```857    ///858    /// {{produces}}859    ///860    /// ### Explanation861    ///862    /// Constants do not have their symbols exported, and therefore, this863    /// probably means you meant to use a [`static`], not a [`const`].864    ///865    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html866    /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html867    NO_MANGLE_CONST_ITEMS,868    Deny,869    "const items will not have their symbols exported"870}871872declare_lint! {873    /// The `no_mangle_generic_items` lint detects generic items that must be874    /// mangled.875    ///876    /// ### Example877    ///878    /// ```rust879    /// #[unsafe(no_mangle)]880    /// fn foo<T>(t: T) {}881    ///882    /// #[unsafe(export_name = "bar")]883    /// fn bar<T>(t: T) {}884    /// ```885    ///886    /// {{produces}}887    ///888    /// ### Explanation889    ///890    /// A function with generics must have its symbol mangled to accommodate891    /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes892    /// have no effect in this situation, and should be removed.893    ///894    /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute895    /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute896    NO_MANGLE_GENERIC_ITEMS,897    Warn,898    "generic items must be mangled"899}900901declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);902903impl InvalidNoMangleItems {904    fn check_no_mangle_on_generic_fn(905        &self,906        cx: &LateContext<'_>,907        attr_span: Span,908        def_id: LocalDefId,909    ) {910        let generics = cx.tcx.generics_of(def_id);911        if generics.requires_monomorphization(cx.tcx) {912            cx.emit_span_lint(913                NO_MANGLE_GENERIC_ITEMS,914                cx.tcx.def_span(def_id),915                BuiltinNoMangleGeneric { suggestion: attr_span },916            );917        }918    }919}920921impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {922    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {923        let attrs = cx.tcx.hir_attrs(it.hir_id());924        match it.kind {925            hir::ItemKind::Fn { .. } => {926                if let Some(attr_span) = find_attr!(attrs, ExportName {span, ..} => *span)927                    .or_else(|| find_attr!(attrs, NoMangle(span) => *span))928                {929                    self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id);930                }931            }932            hir::ItemKind::Const(ident, generics, ..) => {933                if find_attr!(attrs, NoMangle(..)) {934                    let suggestion =935                        if generics.params.is_empty() && generics.where_clause_span.is_empty() {936                            // account for "pub const" (#45562)937                            Some(it.span.until(ident.span))938                        } else {939                            None940                        };941942                    // Const items do not refer to a particular location in memory, and therefore943                    // don't have anything to attach a symbol to944                    cx.emit_span_lint(945                        NO_MANGLE_CONST_ITEMS,946                        it.span,947                        BuiltinConstNoMangle { suggestion },948                    );949                }950            }951            _ => {}952        }953    }954955    fn check_impl_item(&mut self, cx: &LateContext<'_>, it: &hir::ImplItem<'_>) {956        let attrs = cx.tcx.hir_attrs(it.hir_id());957        match it.kind {958            hir::ImplItemKind::Fn { .. } => {959                if let Some(attr_span) = find_attr!(attrs, ExportName {span, ..} => *span)960                    .or_else(|| find_attr!(attrs, NoMangle(span) => *span))961                {962                    self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id);963                }964            }965            _ => {}966        }967    }968}969970declare_lint! {971    /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut972    /// T` because it is [undefined behavior].973    ///974    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html975    ///976    /// ### Example977    ///978    /// ```rust,compile_fail979    /// unsafe {980    ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);981    /// }982    /// ```983    ///984    /// {{produces}}985    ///986    /// ### Explanation987    ///988    /// Certain assumptions are made about aliasing of data, and this transmute989    /// violates those assumptions. Consider using [`UnsafeCell`] instead.990    ///991    /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html992    MUTABLE_TRANSMUTES,993    Deny,994    "transmuting &T to &mut T is undefined behavior, even if the reference is unused"995}996997declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);998999impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {1000    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {1001        if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =1002            get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))1003        {1004            if from_mutbl < to_mutbl {1005                cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);1006            }1007        }10081009        fn get_transmute_from_to<'tcx>(1010            cx: &LateContext<'tcx>,1011            expr: &hir::Expr<'_>,1012        ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {1013            let hir::ExprKind::Path(ref qpath) = expr.kind else { return None };1014            let def = cx.qpath_res(qpath, expr.hir_id);1015            if let Res::Def(DefKind::Fn, did) = def {1016                if !def_id_is_transmute(cx, did) {1017                    return None;1018                }1019                let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);1020                let from = sig.inputs().skip_binder()[0];1021                let to = sig.output().skip_binder();1022                return Some((from, to));1023            }1024            None1025        }10261027        fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {1028            cx.tcx.is_intrinsic(def_id, sym::transmute)1029        }1030    }1031}10321033declare_lint! {1034    /// The `unstable_features` lint detects uses of `#![feature]`.1035    ///1036    /// ### Example1037    ///1038    /// ```rust,compile_fail1039    /// #![deny(unstable_features)]1040    /// #![feature(test)]1041    /// ```1042    ///1043    /// {{produces}}1044    ///1045    /// ### Explanation1046    ///1047    /// In larger nightly-based projects which1048    ///1049    /// * consist of a multitude of crates where a subset of crates has to compile on1050    ///   stable either unconditionally or depending on a `cfg` flag to for example1051    ///   allow stable users to depend on them,1052    /// * don't use nightly for experimental features but for, e.g., unstable options only,1053    ///1054    /// this lint may come in handy to enforce policies of these kinds.1055    UNSTABLE_FEATURES,1056    Allow,1057    "enabling unstable features"1058}10591060declare_lint_pass!(1061    /// Forbids using the `#[feature(...)]` attribute1062    UnstableFeatures => [UNSTABLE_FEATURES]1063);10641065impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {1066    fn check_attributes(&mut self, cx: &LateContext<'_>, attrs: &[hir::Attribute]) {1067        if let Some(features) = find_attr!(attrs, Feature(features, _) => features) {1068            for feature in features {1069                cx.emit_span_lint(UNSTABLE_FEATURES, feature.span, BuiltinUnstableFeatures);1070            }1071        }1072    }1073}10741075declare_lint! {1076    /// The `ungated_async_fn_track_caller` lint warns when the1077    /// `#[track_caller]` attribute is used on an async function1078    /// without enabling the corresponding unstable feature flag.1079    ///1080    /// ### Example1081    ///1082    /// ```rust1083    /// #[track_caller]1084    /// async fn foo() {}1085    /// ```1086    ///1087    /// {{produces}}1088    ///1089    /// ### Explanation1090    ///1091    /// The attribute must be used in conjunction with the1092    /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`1093    /// annotation will function as a no-op.1094    ///1095    /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html1096    UNGATED_ASYNC_FN_TRACK_CALLER,1097    Warn,1098    "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"1099}11001101declare_lint_pass!(1102    /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to1103    /// do anything1104    UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER]1105);11061107impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {1108    fn check_fn(1109        &mut self,1110        cx: &LateContext<'_>,1111        fn_kind: HirFnKind<'_>,1112        _: &'tcx FnDecl<'_>,1113        _: &'tcx Body<'_>,1114        span: Span,1115        def_id: LocalDefId,1116    ) {1117        if fn_kind.asyncness().is_async()1118            && !cx.tcx.features().async_fn_track_caller()1119            // Now, check if the function has the `#[track_caller]` attribute1120            && let Some(attr_span) = find_attr!(cx.tcx, def_id, TrackCaller(span) => *span)1121        {1122            cx.emit_span_lint(1123                UNGATED_ASYNC_FN_TRACK_CALLER,1124                attr_span,1125                BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },1126            );1127        }1128    }1129}11301131declare_lint! {1132    /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that1133    /// means neither directly accessible, nor reexported (with `pub use`), nor leaked through1134    /// things like return types (which the [`unnameable_types`] lint can detect if desired).1135    ///1136    /// ### Example1137    ///1138    /// ```rust,compile_fail1139    /// #![deny(unreachable_pub)]1140    /// mod foo {1141    ///     pub mod bar {1142    ///1143    ///     }1144    /// }1145    /// ```1146    ///1147    /// {{produces}}1148    ///1149    /// ### Explanation1150    ///1151    /// The `pub` keyword both expresses an intent for an item to be publicly available, and also1152    /// signals to the compiler to make the item publicly accessible. The intent can only be1153    /// satisfied, however, if all items which contain this item are *also* publicly accessible.1154    /// Thus, this lint serves to identify situations where the intent does not match the reality.1155    ///1156    /// If you wish the item to be accessible elsewhere within the crate, but not outside it, the1157    /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the1158    /// intent that the item is only visible within its own crate.1159    ///1160    /// This lint is "allow" by default because it will trigger for a large amount of existing Rust code.1161    /// Eventually it is desired for this to become warn-by-default.1162    ///1163    /// [`unnameable_types`]: #unnameable-types1164    pub UNREACHABLE_PUB,1165    Allow,1166    "`pub` items not reachable from crate root"1167}11681169declare_lint_pass!(1170    /// Lint for items marked `pub` that aren't reachable from other crates.1171    UnreachablePub => [UNREACHABLE_PUB]1172);11731174impl UnreachablePub {1175    fn perform_lint(1176        &self,1177        cx: &LateContext<'_>,1178        what: &str,1179        def_id: LocalDefId,1180        vis_span: Span,1181        exportable: bool,1182    ) {1183        let mut applicability = Applicability::MachineApplicable;1184        if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)1185        {1186            // prefer suggesting `pub(super)` instead of `pub(crate)` when possible,1187            // except when `pub(super) == pub(crate)`1188            let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) =1189                cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| {1190                    effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable)1191                })1192                && let parent_parent = cx1193                    .tcx1194                    .parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into())1195                && *restricted_did == parent_parent.to_local_def_id()1196                && !restricted_did.to_def_id().is_crate_root()1197            {1198                "pub(super)"1199            } else {1200                "pub(crate)"1201            };12021203            if vis_span.from_expansion() {1204                applicability = Applicability::MaybeIncorrect;1205            }1206            let def_span = cx.tcx.def_span(def_id);1207            cx.emit_span_lint(1208                UNREACHABLE_PUB,1209                def_span,1210                BuiltinUnreachablePub {1211                    what,1212                    new_vis,1213                    suggestion: (vis_span, applicability),1214                    help: exportable,1215                },1216            );1217        }1218    }1219}12201221impl<'tcx> LateLintPass<'tcx> for UnreachablePub {1222    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {1223        // Do not warn for fake `use` statements.1224        if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {1225            return;1226        }1227        self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);1228    }12291230    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {1231        self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);1232    }12331234    fn check_field_def(&mut self, _cx: &LateContext<'_>, _field: &hir::FieldDef<'_>) {1235        // - If an ADT definition is reported then we don't need to check fields1236        //   (as it would add unnecessary complexity to the source code, the struct1237        //   definition is in the immediate proximity to give the "real" visibility).1238        // - If an ADT is not reported because it's not `pub` - we don't need to1239        //   check fields.1240        // - If an ADT is not reported because it's reachable - we also don't need1241        //   to check fields because then they are reachable by construction if they1242        //   are pub.1243        //1244        // Therefore in no case we check the fields.1245        //1246        // cf. https://github.com/rust-lang/rust/pull/126013#issuecomment-21528392051247        // cf. https://github.com/rust-lang/rust/pull/126040#issuecomment-21529445061248    }12491250    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {1251        if let ImplItemImplKind::Inherent { vis_span } = impl_item.impl_kind {1252            self.perform_lint(cx, "item", impl_item.owner_id.def_id, vis_span, false);1253        }1254    }1255}12561257declare_lint! {1258    /// The `type_alias_bounds` lint detects bounds in type aliases.1259    ///1260    /// ### Example1261    ///1262    /// ```rust1263    /// type SendVec<T: Send> = Vec<T>;1264    /// ```1265    ///1266    /// {{produces}}1267    ///1268    /// ### Explanation1269    ///1270    /// Trait and lifetime bounds on generic parameters and in where clauses of1271    /// type aliases are not checked at usage sites of the type alias. Moreover,1272    /// they are not thoroughly checked for correctness at their definition site1273    /// either similar to the aliased type.1274    ///1275    /// This is a known limitation of the type checker that may be lifted in a1276    /// future edition. Permitting such bounds in light of this was unintentional.1277    ///1278    /// While these bounds may have secondary effects such as enabling the use of1279    /// "shorthand" associated type paths[^1] and affecting the default trait1280    /// object lifetime[^2] of trait object types passed to the type alias, this1281    /// should not have been allowed until the aforementioned restrictions of the1282    /// type checker have been lifted.1283    ///1284    /// Using such bounds is highly discouraged as they are actively misleading.1285    ///1286    /// [^1]: I.e., paths of the form `T::Assoc` where `T` is a type parameter1287    /// bounded by trait `Trait` which defines an associated type called `Assoc`1288    /// as opposed to a fully qualified path of the form `<T as Trait>::Assoc`.1289    /// [^2]: <https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes>1290    TYPE_ALIAS_BOUNDS,1291    Warn,1292    "bounds in type aliases are not enforced"1293}12941295declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]);12961297impl TypeAliasBounds {1298    pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool {1299        // Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults.1300        if let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind1301            && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_)))1302            && pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS1303            && pred.bounded_ty.as_generic_param().is_some()1304        {1305            return true;1306        }1307        false1308    }1309}13101311impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {1312    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {1313        let hir::ItemKind::TyAlias(_, generics, hir_ty) = item.kind else { return };13141315        // There must not be a where clause.1316        if generics.predicates.is_empty() {1317            return;1318        }13191320        // Bounds of lazy type aliases and TAITs are respected.1321        if cx.tcx.type_alias_is_lazy(item.owner_id) {1322            return;1323        }13241325        // FIXME(generic_const_exprs): Revisit this before stabilization.1326        // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`.1327        let ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip();1328        if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)1329            && cx.tcx.features().generic_const_exprs()1330        {1331            return;1332        }13331334        // NOTE(inherent_associated_types): While we currently do take some bounds in type1335        // aliases into consideration during IAT *selection*, we don't perform full use+def1336        // site wfchecking for such type aliases. Therefore TAB should still trigger.1337        // See also `tests/ui/associated-inherent-types/type-alias-bounds.rs`.13381339        let mut where_spans = Vec::new();1340        let mut inline_spans = Vec::new();1341        let mut inline_sugg = Vec::new();13421343        for p in generics.predicates {1344            let span = p.span;1345            if p.kind.in_where_clause() {1346                where_spans.push(span);1347            } else {1348                for b in p.kind.bounds() {1349                    inline_spans.push(b.span());1350                }1351                inline_sugg.push((span, String::new()));1352            }1353        }13541355        let mut ty = Some(hir_ty);1356        let enable_feat_help = cx.tcx.sess.is_nightly_build();13571358        if let [.., label_sp] = *where_spans {1359            cx.emit_span_lint(1360                TYPE_ALIAS_BOUNDS,1361                where_spans,1362                BuiltinTypeAliasBounds {1363                    in_where_clause: true,1364                    label: label_sp,1365                    enable_feat_help,1366                    suggestions: vec![(generics.where_clause_span, String::new())],1367                    preds: generics.predicates,1368                    ty: ty.take(),1369                },1370            );1371        }1372        if let [.., label_sp] = *inline_spans {1373            cx.emit_span_lint(1374                TYPE_ALIAS_BOUNDS,1375                inline_spans,1376                BuiltinTypeAliasBounds {1377                    in_where_clause: false,1378                    label: label_sp,1379                    enable_feat_help,1380                    suggestions: inline_sugg,1381                    preds: generics.predicates,1382                    ty,1383                },1384            );1385        }1386    }1387}13881389pub(crate) struct ShorthandAssocTyCollector {1390    pub(crate) qselves: Vec<Span>,1391}13921393impl hir::intravisit::Visitor<'_> for ShorthandAssocTyCollector {1394    fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) {1395        // Look for "type-parameter shorthand-associated-types". I.e., paths of the1396        // form `T::Assoc` with `T` type param. These are reliant on trait bounds.1397        if let hir::QPath::TypeRelative(qself, _) = qpath1398            && qself.as_generic_param().is_some()1399        {1400            self.qselves.push(qself.span);1401        }1402        hir::intravisit::walk_qpath(self, qpath, id)1403    }1404}14051406declare_lint! {1407    /// The `trivial_bounds` lint detects trait bounds that don't depend on1408    /// any type parameters.1409    ///1410    /// ### Example1411    ///1412    /// ```rust1413    /// #![feature(trivial_bounds)]1414    /// pub struct A where i32: Copy;1415    /// ```1416    ///1417    /// {{produces}}1418    ///1419    /// ### Explanation1420    ///1421    /// Usually you would not write a trait bound that you know is always1422    /// true, or never true. However, when using macros, the macro may not1423    /// know whether or not the constraint would hold or not at the time when1424    /// generating the code. Currently, the compiler does not alert you if the1425    /// constraint is always true, and generates an error if it is never true.1426    /// The `trivial_bounds` feature changes this to be a warning in both1427    /// cases, giving macros more freedom and flexibility to generate code,1428    /// while still providing a signal when writing non-macro code that1429    /// something is amiss.1430    ///1431    /// See [RFC 2056] for more details. This feature is currently only1432    /// available on the nightly channel, see [tracking issue #48214].1433    ///1434    /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md1435    /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/482141436    TRIVIAL_BOUNDS,1437    Warn,1438    "these bounds don't depend on an type parameters"1439}14401441declare_lint_pass!(1442    /// Lint for trait and lifetime bounds that don't depend on type parameters1443    /// which either do nothing, or stop the item from being used.1444    TrivialConstraints => [TRIVIAL_BOUNDS]1445);14461447impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {1448    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {1449        use rustc_middle::ty::ClauseKind;14501451        if cx.tcx.features().trivial_bounds() {1452            let predicates = cx.tcx.predicates_of(item.owner_id);1453            for &(predicate, span) in predicates.predicates {1454                let predicate_kind_name = match predicate.kind().skip_binder() {1455                    ClauseKind::Trait(..) => "trait",1456                    ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime",14571458                    ClauseKind::UnstableFeature(_)1459                    // `ConstArgHasType` is never global as `ct` is always a param1460                    | ClauseKind::ConstArgHasType(..)1461                    // Ignore projections, as they can only be global1462                    // if the trait bound is global1463                    | ClauseKind::Projection(..)1464                    // Ignore bounds that a user can't type1465                    | ClauseKind::WellFormed(..)1466                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written1467                    | ClauseKind::ConstEvaluatable(..)1468                    // Users don't write this directly, only via another trait ref.1469                    | ty::ClauseKind::HostEffect(..) => continue,1470                };1471                if predicate.is_global() {1472                    cx.emit_span_lint(1473                        TRIVIAL_BOUNDS,1474                        span,1475                        BuiltinTrivialBounds { predicate_kind_name, predicate },1476                    );1477                }1478            }1479        }1480    }1481}14821483declare_lint! {1484    /// The `double_negations` lint detects expressions of the form `--x`.1485    ///1486    /// ### Example1487    ///1488    /// ```rust1489    /// fn main() {1490    ///     let x = 1;1491    ///     let _b = --x;1492    /// }1493    /// ```1494    ///1495    /// {{produces}}1496    ///1497    /// ### Explanation1498    ///1499    /// Negating something twice is usually the same as not negating it at all.1500    /// However, a double negation in Rust can easily be confused with the1501    /// prefix decrement operator that exists in many languages derived from C.1502    /// Use `-(-x)` if you really wanted to negate the value twice.1503    ///1504    /// To decrement a value, use `x -= 1` instead.1505    pub DOUBLE_NEGATIONS,1506    Warn,1507    "detects expressions of the form `--x`"1508}15091510declare_lint_pass!(1511    /// Lint for expressions of the form `--x` that can be confused with C's1512    /// prefix decrement operator.1513    DoubleNegations => [DOUBLE_NEGATIONS]1514);15151516impl EarlyLintPass for DoubleNegations {1517    #[inline]1518    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {1519        // only lint on the innermost `--` in a chain of `-` operators,1520        // even if there are 3 or more negations1521        if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind1522            && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind1523            && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))1524            // Don't lint if this jumps macro expansion boundary (Issue #143980)1525            && expr.span.eq_ctxt(inner.span)1526        {1527            cx.emit_span_lint(1528                DOUBLE_NEGATIONS,1529                expr.span,1530                BuiltinDoubleNegations {1531                    add_parens: BuiltinDoubleNegationsAddParens {1532                        start_span: inner.span.shrink_to_lo(),1533                        end_span: inner.span.shrink_to_hi(),1534                    },1535                },1536            );1537        }1538    }1539}15401541pub mod soft {1542    use super::*;15431544    pub fn lint_vec() -> crate::LintVec {1545        vec![1546            WHILE_TRUE,1547            NON_SHORTHAND_FIELD_PATTERNS,1548            UNSAFE_CODE,1549            MISSING_DOCS,1550            MISSING_COPY_IMPLEMENTATIONS,1551            MISSING_DEBUG_IMPLEMENTATIONS,1552            ANONYMOUS_PARAMETERS,1553            UNUSED_DOC_COMMENTS,1554            NO_MANGLE_CONST_ITEMS,1555            NO_MANGLE_GENERIC_ITEMS,1556            MUTABLE_TRANSMUTES,1557            UNSTABLE_FEATURES,1558            UNREACHABLE_PUB,1559            TYPE_ALIAS_BOUNDS,1560            TRIVIAL_BOUNDS,1561            DOUBLE_NEGATIONS,1562        ]1563    }1564}15651566declare_lint! {1567    /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range1568    /// pattern], which is deprecated.1569    ///1570    /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns1571    ///1572    /// ### Example1573    ///1574    /// ```rust,edition20181575    /// let x = 123;1576    /// match x {1577    ///     0...100 => {}1578    ///     _ => {}1579    /// }1580    /// ```1581    ///1582    /// {{produces}}1583    ///1584    /// ### Explanation1585    ///1586    /// The `...` range pattern syntax was changed to `..=` to avoid potential1587    /// confusion with the [`..` range expression]. Use the new form instead.1588    ///1589    /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html1590    pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,1591    Warn,1592    "`...` range patterns are deprecated",1593    @future_incompatible = FutureIncompatibleInfo {1594        reason: fcw!(EditionError 2021 "warnings-promoted-to-error"),1595    };1596}15971598#[derive(Default)]1599pub struct EllipsisInclusiveRangePatterns {1600    /// If `Some(_)`, suppress all subsequent pattern1601    /// warnings for better diagnostics.1602    node_id: Option<ast::NodeId>,1603}16041605impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);16061607impl EarlyLintPass for EllipsisInclusiveRangePatterns {1608    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {1609        if self.node_id.is_some() {1610            // Don't recursively warn about patterns inside range endpoints.1611            return;1612        }16131614        use self::ast::PatKind;1615        use self::ast::RangeSyntax::DotDotDot;16161617        /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span1618        /// corresponding to the ellipsis.1619        fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {1620            match &pat.kind {1621                PatKind::Range(1622                    a,1623                    Some(b),1624                    Spanned { span, node: RangeEnd::Included(DotDotDot) },1625                ) => Some((a.as_deref(), b, *span)),1626                _ => None,1627            }1628        }16291630        let (parentheses, endpoints) = match &pat.kind {1631            PatKind::Ref(subpat, _, _) => (true, matches_ellipsis_pat(subpat)),1632            _ => (false, matches_ellipsis_pat(pat)),1633        };16341635        if let Some((start, end, join)) = endpoints {1636            if parentheses {1637                self.node_id = Some(pat.id);1638                let end = expr_to_string(end);1639                let replace = match start {1640                    Some(start) => format!("&({}..={})", expr_to_string(start), end),1641                    None => format!("&(..={end})"),1642                };1643                if join.edition() >= Edition::Edition2021 {1644                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {1645                        span: pat.span,1646                        suggestion: pat.span,1647                        replace,1648                    });1649                } else {1650                    cx.emit_span_lint(1651                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,1652                        pat.span,1653                        BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {1654                            suggestion: pat.span,1655                            replace,1656                        },1657                    );1658                }1659            } else {1660                let replace = "..=";1661                if join.edition() >= Edition::Edition2021 {1662                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {1663                        span: pat.span,1664                        suggestion: join,1665                        replace: replace.to_string(),1666                    });1667                } else {1668                    cx.emit_span_lint(1669                        ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,1670                        join,1671                        BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {1672                            suggestion: join,1673                        },1674                    );1675                }1676            };1677        }1678    }16791680    fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {1681        if let Some(node_id) = self.node_id {1682            if pat.id == node_id {1683                self.node_id = None1684            }1685        }1686    }1687}16881689declare_lint! {1690    /// The `keyword_idents_2018` lint detects edition keywords being used as an1691    /// identifier.1692    ///1693    /// ### Example1694    ///1695    /// ```rust,edition2015,compile_fail1696    /// #![deny(keyword_idents_2018)]1697    /// // edition 20151698    /// fn dyn() {}1699    /// ```1700    ///1701    /// {{produces}}1702    ///1703    /// ### Explanation1704    ///1705    /// Rust [editions] allow the language to evolve without breaking1706    /// backwards compatibility. This lint catches code that uses new keywords1707    /// that are added to the language that are used as identifiers (such as a1708    /// variable name, function name, etc.). If you switch the compiler to a1709    /// new edition without updating the code, then it will fail to compile if1710    /// you are using a new keyword as an identifier.1711    ///1712    /// You can manually change the identifiers to a non-keyword, or use a1713    /// [raw identifier], for example `r#dyn`, to transition to a new edition.1714    ///1715    /// This lint solves the problem automatically. It is "allow" by default1716    /// because the code is perfectly valid in older editions. The [`cargo1717    /// fix`] tool with the `--edition` flag will switch this lint to "warn"1718    /// and automatically apply the suggested fix from the compiler (which is1719    /// to use a raw identifier). This provides a completely automated way to1720    /// update old code for a new edition.1721    ///1722    /// [editions]: https://doc.rust-lang.org/edition-guide/1723    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html1724    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html1725    pub KEYWORD_IDENTS_2018,1726    Allow,1727    "detects edition keywords being used as an identifier",1728    @future_incompatible = FutureIncompatibleInfo {1729        reason: fcw!(EditionError 2018 "new-keywords"),1730    };1731}17321733declare_lint! {1734    /// The `keyword_idents_2024` lint detects edition keywords being used as an1735    /// identifier.1736    ///1737    /// ### Example1738    ///1739    /// ```rust,edition2015,compile_fail1740    /// #![deny(keyword_idents_2024)]1741    /// // edition 20151742    /// fn gen() {}1743    /// ```1744    ///1745    /// {{produces}}1746    ///1747    /// ### Explanation1748    ///1749    /// Rust [editions] allow the language to evolve without breaking1750    /// backwards compatibility. This lint catches code that uses new keywords1751    /// that are added to the language that are used as identifiers (such as a1752    /// variable name, function name, etc.). If you switch the compiler to a1753    /// new edition without updating the code, then it will fail to compile if1754    /// you are using a new keyword as an identifier.1755    ///1756    /// You can manually change the identifiers to a non-keyword, or use a1757    /// [raw identifier], for example `r#gen`, to transition to a new edition.1758    ///1759    /// This lint solves the problem automatically. It is "allow" by default1760    /// because the code is perfectly valid in older editions. The [`cargo1761    /// fix`] tool with the `--edition` flag will switch this lint to "warn"1762    /// and automatically apply the suggested fix from the compiler (which is1763    /// to use a raw identifier). This provides a completely automated way to1764    /// update old code for a new edition.1765    ///1766    /// [editions]: https://doc.rust-lang.org/edition-guide/1767    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html1768    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html1769    pub KEYWORD_IDENTS_2024,1770    Allow,1771    "detects edition keywords being used as an identifier",1772    @future_incompatible = FutureIncompatibleInfo {1773        reason: fcw!(EditionError 2024 "gen-keyword"),1774    };1775}17761777declare_lint_pass!(1778    /// Check for uses of edition keywords used as an identifier.1779    KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]1780);17811782struct UnderMacro(bool);17831784impl KeywordIdents {1785    fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {1786        // Check if the preceding token is `$`, because we want to allow `$async`, etc.1787        let mut prev_dollar = false;1788        for tt in tokens.iter() {1789            match tt {1790                // Only report non-raw idents.1791                TokenTree::Token(token, _) => {1792                    if let Some((ident, token::IdentIsRaw::No)) = token.ident() {1793                        if !prev_dollar {1794                            self.check_ident_token(cx, UnderMacro(true), ident, "");1795                        }1796                    } else if let Some((ident, token::IdentIsRaw::No)) = token.lifetime() {1797                        self.check_ident_token(1798                            cx,1799                            UnderMacro(true),1800                            ident.without_first_quote(),1801                            "'",1802                        );1803                    } else if token.kind == TokenKind::Dollar {1804                        prev_dollar = true;1805                        continue;1806                    }1807                }1808                TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),1809            }1810            prev_dollar = false;1811        }1812    }18131814    fn check_ident_token(1815        &mut self,1816        cx: &EarlyContext<'_>,1817        UnderMacro(under_macro): UnderMacro,1818        ident: Ident,1819        prefix: &'static str,1820    ) {1821        let (lint, edition) = match ident.name {1822            kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),18231824            // rust-lang/rust#56327: Conservatively do not1825            // attempt to report occurrences of `dyn` within1826            // macro definitions or invocations, because `dyn`1827            // can legitimately occur as a contextual keyword1828            // in 2015 code denoting its 2018 meaning, and we1829            // do not want rustfix to inject bugs into working1830            // code by rewriting such occurrences.1831            //1832            // But if we see `dyn` outside of a macro, we know1833            // its precise role in the parsed AST and thus are1834            // assured this is truly an attempt to use it as1835            // an identifier.1836            kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),18371838            kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),18391840            _ => return,1841        };18421843        // Don't lint `r#foo`.1844        if ident.span.edition() >= edition1845            || cx.sess().psess.raw_identifier_spans.contains(ident.span)1846        {1847            return;1848        }18491850        cx.emit_span_lint(1851            lint,1852            ident.span,1853            BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix },1854        );1855    }1856}18571858impl EarlyLintPass for KeywordIdents {1859    fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {1860        self.check_tokens(cx, &mac_def.body.tokens);1861    }1862    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {1863        self.check_tokens(cx, &mac.args.tokens);1864    }1865    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) {1866        if ident.name.as_str().starts_with('\'') {1867            self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'");1868        } else {1869            self.check_ident_token(cx, UnderMacro(false), *ident, "");1870        }1871    }1872}18731874declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);18751876impl ExplicitOutlivesRequirements {1877    fn lifetimes_outliving_lifetime<'tcx>(1878        tcx: TyCtxt<'tcx>,1879        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,1880        item: LocalDefId,1881        lifetime: LocalDefId,1882    ) -> Vec<ty::Region<'tcx>> {1883        let item_generics = tcx.generics_of(item);18841885        inferred_outlives1886            .filter_map(|(clause, _)| match clause.kind().skip_binder() {1887                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a.kind() {1888                    ty::ReEarlyParam(ebr)1889                        if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() =>1890                    {1891                        Some(b)1892                    }1893                    _ => None,1894                },1895                _ => None,1896            })1897            .collect()1898    }18991900    fn lifetimes_outliving_type<'tcx>(1901        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,1902        index: u32,1903    ) -> Vec<ty::Region<'tcx>> {1904        inferred_outlives1905            .filter_map(|(clause, _)| match clause.kind().skip_binder() {1906                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {1907                    a.is_param(index).then_some(b)1908                }1909                _ => None,1910            })1911            .collect()1912    }19131914    fn collect_outlives_bound_spans<'tcx>(1915        &self,1916        tcx: TyCtxt<'tcx>,1917        bounds: &hir::GenericBounds<'_>,1918        inferred_outlives: &[ty::Region<'tcx>],1919        predicate_span: Span,1920        item: DefId,1921    ) -> Vec<(usize, Span)> {1922        use rustc_middle::middle::resolve_bound_vars::ResolvedArg;19231924        let item_generics = tcx.generics_of(item);19251926        bounds1927            .iter()1928            .enumerate()1929            .filter_map(|(i, bound)| {1930                let hir::GenericBound::Outlives(lifetime) = bound else {1931                    return None;1932                };19331934                let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {1935                    Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives1936                        .iter()1937                        .any(|r| matches!(r.kind(), ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })),1938                    _ => false,1939                };19401941                if !is_inferred {1942                    return None;1943                }19441945                let span = bound.span().find_ancestor_inside(predicate_span)?;1946                if span.in_external_macro(tcx.sess.source_map()) {1947                    return None;1948                }19491950                Some((i, span))1951            })1952            .collect()1953    }19541955    fn consolidate_outlives_bound_spans(1956        &self,1957        lo: Span,1958        bounds: &hir::GenericBounds<'_>,1959        bound_spans: Vec<(usize, Span)>,1960    ) -> Vec<Span> {1961        if bounds.is_empty() {1962            return Vec::new();1963        }1964        if bound_spans.len() == bounds.len() {1965            let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];1966            // If all bounds are inferable, we want to delete the colon, so1967            // start from just after the parameter (span passed as argument)1968            vec![lo.to(last_bound_span)]1969        } else {1970            let mut merged = Vec::new();1971            let mut last_merged_i = None;19721973            let mut from_start = true;1974            for (i, bound_span) in bound_spans {1975                match last_merged_i {1976                    // If the first bound is inferable, our span should also eat the leading `+`.1977                    None if i == 0 => {1978                        merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));1979                        last_merged_i = Some(0);1980                    }1981                    // If consecutive bounds are inferable, merge their spans1982                    Some(h) if i == h + 1 => {1983                        if let Some(tail) = merged.last_mut() {1984                            // Also eat the trailing `+` if the first1985                            // more-than-one bound is inferable1986                            let to_span = if from_start && i < bounds.len() {1987                                bounds[i + 1].span().shrink_to_lo()1988                            } else {1989                                bound_span1990                            };1991                            *tail = tail.to(to_span);1992                            last_merged_i = Some(i);1993                        } else {1994                            bug!("another bound-span visited earlier");1995                        }1996                    }1997                    _ => {1998                        // When we find a non-inferable bound, subsequent inferable bounds1999                        // won't be consecutive from the start (and we'll eat the leading2000                        // `+` rather than the trailing one)

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.