1 //! Lints in the Rust compiler.
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.
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 //! You can do that in an existing `LintPass` if it makes sense, or in a
10 //! new `LintPass`, or using `Session::add_lint` elsewhere in the
11 //! compiler. Only do the latter if the check can't be written cleanly as a
12 //! `LintPass` (also, note that such lints will need to be defined in
13 //! `rustc_session::lint::builtin`, not here).
15 //! If you define a new `EarlyLintPass`, you will also need to add it to the
16 //! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
17 //! `lib.rs`. Use the former for unit-like structs and the latter for structs
18 //! with a `pub fn new()`.
20 //! If you define a new `LateLintPass`, you will also need to add it to the
21 //! `late_lint_methods!` invocation in `lib.rs`.
23 use crate::fluent_generated
as fluent
;
25 errors
::BuiltinEllipsisInclusiveRangePatterns
,
27 BuiltinAnonymousParams
, BuiltinBoxPointers
, BuiltinConstNoMangle
,
28 BuiltinDeprecatedAttrLink
, BuiltinDeprecatedAttrLinkSuggestion
, BuiltinDeprecatedAttrUsed
,
29 BuiltinDerefNullptr
, BuiltinEllipsisInclusiveRangePatternsLint
, BuiltinExplicitOutlives
,
30 BuiltinExplicitOutlivesSuggestion
, BuiltinFeatureIssueNote
, BuiltinIncompleteFeatures
,
31 BuiltinIncompleteFeaturesHelp
, BuiltinInternalFeatures
, BuiltinKeywordIdents
,
32 BuiltinMissingCopyImpl
, BuiltinMissingDebugImpl
, BuiltinMissingDoc
,
33 BuiltinMutablesTransmutes
, BuiltinNoMangleGeneric
, BuiltinNonShorthandFieldPatterns
,
34 BuiltinSpecialModuleNameUsed
, BuiltinTrivialBounds
, BuiltinTypeAliasGenericBounds
,
35 BuiltinTypeAliasGenericBoundsSuggestion
, BuiltinTypeAliasWhereClause
,
36 BuiltinUnexpectedCliConfigName
, BuiltinUnexpectedCliConfigValue
,
37 BuiltinUngatedAsyncFnTrackCaller
, BuiltinUnpermittedTypeInit
,
38 BuiltinUnpermittedTypeInitSub
, BuiltinUnreachablePub
, BuiltinUnsafe
,
39 BuiltinUnstableFeatures
, BuiltinUnusedDocComment
, BuiltinUnusedDocCommentSub
,
40 BuiltinWhileTrue
, SuggestChangingAssocTypes
,
42 EarlyContext
, EarlyLintPass
, LateContext
, LateLintPass
, Level
, LintContext
,
45 use rustc_ast
::tokenstream
::{TokenStream, TokenTree}
;
46 use rustc_ast
::visit
::{FnCtxt, FnKind}
;
47 use rustc_ast
::{self as ast, *}
;
48 use rustc_ast_pretty
::pprust
::{self, expr_to_string}
;
49 use rustc_errors
::{Applicability, DecorateLint, MultiSpan}
;
50 use rustc_feature
::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}
;
52 use rustc_hir
::def
::{DefKind, Res}
;
53 use rustc_hir
::def_id
::{DefId, LocalDefId, CRATE_DEF_ID}
;
54 use rustc_hir
::intravisit
::FnKind
as HirFnKind
;
55 use rustc_hir
::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}
;
56 use rustc_middle
::lint
::in_external_macro
;
57 use rustc_middle
::ty
::layout
::LayoutOf
;
58 use rustc_middle
::ty
::print
::with_no_trimmed_paths
;
59 use rustc_middle
::ty
::GenericArgKind
;
60 use rustc_middle
::ty
::ToPredicate
;
61 use rustc_middle
::ty
::TypeVisitableExt
;
62 use rustc_middle
::ty
::{self, Ty, TyCtxt, VariantDef}
;
63 use rustc_session
::config
::ExpectedValues
;
64 use rustc_session
::lint
::{BuiltinLintDiagnostics, FutureIncompatibilityReason}
;
65 use rustc_span
::edition
::Edition
;
66 use rustc_span
::source_map
::Spanned
;
67 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
68 use rustc_span
::{BytePos, InnerSpan, Span}
;
69 use rustc_target
::abi
::Abi
;
70 use rustc_trait_selection
::infer
::{InferCtxtExt, TyCtxtInferExt}
;
71 use rustc_trait_selection
::traits
::query
::evaluate_obligation
::InferCtxtExt
as _
;
72 use rustc_trait_selection
::traits
::{self, misc::type_allowed_to_implement_copy}
;
74 use crate::nonstandard_style
::{method_context, MethodLateContext}
;
78 // hardwired lints from librustc_middle
79 pub use rustc_session
::lint
::builtin
::*;
82 /// The `while_true` lint detects `while true { }`.
96 /// `while true` should be replaced with `loop`. A `loop` expression is
97 /// the preferred way to write an infinite loop because it more directly
98 /// expresses the intent of the loop.
101 "suggest using `loop { }` instead of `while true { }`"
104 declare_lint_pass
!(WhileTrue
=> [WHILE_TRUE
]);
106 /// Traverse through any amount of parenthesis and return the first non-parens expression.
107 fn pierce_parens(mut expr
: &ast
::Expr
) -> &ast
::Expr
{
108 while let ast
::ExprKind
::Paren(sub
) = &expr
.kind
{
114 impl EarlyLintPass
for WhileTrue
{
116 fn check_expr(&mut self, cx
: &EarlyContext
<'_
>, e
: &ast
::Expr
) {
117 if let ast
::ExprKind
::While(cond
, _
, label
) = &e
.kind
118 && let ast
::ExprKind
::Lit(token_lit
) = pierce_parens(cond
).kind
119 && let token
::Lit { kind: token::Bool, symbol: kw::True, .. }
= token_lit
120 && !cond
.span
.from_expansion()
122 let condition_span
= e
.span
.with_hi(cond
.span
.hi());
123 let replace
= format
!(
125 label
.map_or_else(String
::new
, |label
| format
!("{}: ", label
.ident
,))
127 cx
.emit_spanned_lint(
130 BuiltinWhileTrue { suggestion: condition_span, replace }
,
137 /// The `box_pointers` lints use of the Box type.
141 /// ```rust,compile_fail
142 /// #![deny(box_pointers)]
152 /// This lint is mostly historical, and not particularly useful. `Box<T>`
153 /// used to be built into the language, and the only way to do heap
154 /// allocation. Today's Rust can call into other allocators, etc.
157 "use of owned (Box type) heap memory"
160 declare_lint_pass
!(BoxPointers
=> [BOX_POINTERS
]);
163 fn check_heap_type(&self, cx
: &LateContext
<'_
>, span
: Span
, ty
: Ty
<'_
>) {
164 for leaf
in ty
.walk() {
165 if let GenericArgKind
::Type(leaf_ty
) = leaf
.unpack()
168 cx
.emit_spanned_lint(BOX_POINTERS
, span
, BuiltinBoxPointers { ty }
);
174 impl<'tcx
> LateLintPass
<'tcx
> for BoxPointers
{
175 fn check_item(&mut self, cx
: &LateContext
<'_
>, it
: &hir
::Item
<'_
>) {
177 hir
::ItemKind
::Fn(..)
178 | hir
::ItemKind
::TyAlias(..)
179 | hir
::ItemKind
::Enum(..)
180 | hir
::ItemKind
::Struct(..)
181 | hir
::ItemKind
::Union(..) => self.check_heap_type(
184 cx
.tcx
.type_of(it
.owner_id
).instantiate_identity(),
189 // If it's a struct, we also have to check the fields' types
191 hir
::ItemKind
::Struct(ref struct_def
, _
) | hir
::ItemKind
::Union(ref struct_def
, _
) => {
192 for field
in struct_def
.fields() {
193 self.check_heap_type(
196 cx
.tcx
.type_of(field
.def_id
).instantiate_identity(),
204 fn check_expr(&mut self, cx
: &LateContext
<'_
>, e
: &hir
::Expr
<'_
>) {
205 let ty
= cx
.typeck_results().node_type(e
.hir_id
);
206 self.check_heap_type(cx
, e
.span
, ty
);
211 /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
212 /// instead of `Struct { x }` in a pattern.
230 /// Point { x: x, y: y } => (),
239 /// The preferred style is to avoid the repetition of specifying both the
240 /// field name and the binding name if both identifiers are the same.
241 NON_SHORTHAND_FIELD_PATTERNS
,
243 "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
246 declare_lint_pass
!(NonShorthandFieldPatterns
=> [NON_SHORTHAND_FIELD_PATTERNS
]);
248 impl<'tcx
> LateLintPass
<'tcx
> for NonShorthandFieldPatterns
{
249 fn check_pat(&mut self, cx
: &LateContext
<'_
>, pat
: &hir
::Pat
<'_
>) {
250 if let PatKind
::Struct(ref qpath
, field_pats
, _
) = pat
.kind
{
255 .expect("struct pattern type is not an ADT")
256 .variant_of_res(cx
.qpath_res(qpath
, pat
.hir_id
));
257 for fieldpat
in field_pats
{
258 if fieldpat
.is_shorthand
{
261 if fieldpat
.span
.from_expansion() {
262 // Don't lint if this is a macro expansion: macro authors
263 // shouldn't have to worry about this kind of style issue
267 if let PatKind
::Binding(binding_annot
, _
, ident
, None
) = fieldpat
.pat
.kind
{
268 if cx
.tcx
.find_field_index(ident
, &variant
)
269 == Some(cx
.typeck_results().field_index(fieldpat
.hir_id
))
271 cx
.emit_spanned_lint(
272 NON_SHORTHAND_FIELD_PATTERNS
,
274 BuiltinNonShorthandFieldPatterns
{
276 suggestion
: fieldpat
.span
,
277 prefix
: binding_annot
.prefix_str(),
288 /// The `unsafe_code` lint catches usage of `unsafe` code and other
289 /// potentially unsound constructs like `no_mangle`, `export_name`,
290 /// and `link_section`.
294 /// ```rust,compile_fail
295 /// #![deny(unsafe_code)]
305 /// #[export_name = "exported_symbol_name"]
306 /// pub fn name_in_rust() { }
309 /// #[link_section = ".example_section"]
310 /// pub static VAR1: u32 = 1;
317 /// This lint is intended to restrict the usage of `unsafe` blocks and other
318 /// constructs (including, but not limited to `no_mangle`, `link_section`
319 /// and `export_name` attributes) wrong usage of which causes undefined
323 "usage of `unsafe` code and other potentially unsound constructs"
326 declare_lint_pass
!(UnsafeCode
=> [UNSAFE_CODE
]);
331 cx
: &EarlyContext
<'_
>,
333 decorate
: impl for<'a
> DecorateLint
<'a
, ()>,
335 // This comes from a macro that has `#[allow_internal_unsafe]`.
336 if span
.allows_unsafe() {
340 cx
.emit_spanned_lint(UNSAFE_CODE
, span
, decorate
);
344 impl EarlyLintPass
for UnsafeCode
{
345 fn check_attribute(&mut self, cx
: &EarlyContext
<'_
>, attr
: &ast
::Attribute
) {
346 if attr
.has_name(sym
::allow_internal_unsafe
) {
347 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::AllowInternalUnsafe
);
352 fn check_expr(&mut self, cx
: &EarlyContext
<'_
>, e
: &ast
::Expr
) {
353 if let ast
::ExprKind
::Block(ref blk
, _
) = e
.kind
{
354 // Don't warn about generated blocks; that'll just pollute the output.
355 if blk
.rules
== ast
::BlockCheckMode
::Unsafe(ast
::UserProvided
) {
356 self.report_unsafe(cx
, blk
.span
, BuiltinUnsafe
::UnsafeBlock
);
361 fn check_item(&mut self, cx
: &EarlyContext
<'_
>, it
: &ast
::Item
) {
363 ast
::ItemKind
::Trait(box ast
::Trait { unsafety: ast::Unsafe::Yes(_), .. }
) => {
364 self.report_unsafe(cx
, it
.span
, BuiltinUnsafe
::UnsafeTrait
);
367 ast
::ItemKind
::Impl(box ast
::Impl { unsafety: ast::Unsafe::Yes(_), .. }
) => {
368 self.report_unsafe(cx
, it
.span
, BuiltinUnsafe
::UnsafeImpl
);
371 ast
::ItemKind
::Fn(..) => {
372 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::no_mangle
) {
373 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::NoMangleFn
);
376 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::export_name
) {
377 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::ExportNameFn
);
380 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::link_section
) {
381 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::LinkSectionFn
);
385 ast
::ItemKind
::Static(..) => {
386 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::no_mangle
) {
387 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::NoMangleStatic
);
390 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::export_name
) {
391 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::ExportNameStatic
);
394 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::link_section
) {
395 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::LinkSectionStatic
);
403 fn check_impl_item(&mut self, cx
: &EarlyContext
<'_
>, it
: &ast
::AssocItem
) {
404 if let ast
::AssocItemKind
::Fn(..) = it
.kind
{
405 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::no_mangle
) {
406 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::NoMangleMethod
);
408 if let Some(attr
) = attr
::find_by_name(&it
.attrs
, sym
::export_name
) {
409 self.report_unsafe(cx
, attr
.span
, BuiltinUnsafe
::ExportNameMethod
);
414 fn check_fn(&mut self, cx
: &EarlyContext
<'_
>, fk
: FnKind
<'_
>, span
: Span
, _
: ast
::NodeId
) {
418 ast
::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }
, .. },
424 let decorator
= match ctxt
{
425 FnCtxt
::Foreign
=> return,
426 FnCtxt
::Free
=> BuiltinUnsafe
::DeclUnsafeFn
,
427 FnCtxt
::Assoc(_
) if body
.is_none() => BuiltinUnsafe
::DeclUnsafeMethod
,
428 FnCtxt
::Assoc(_
) => BuiltinUnsafe
::ImplUnsafeMethod
,
430 self.report_unsafe(cx
, span
, decorator
);
436 /// The `missing_docs` lint detects missing documentation for public items.
440 /// ```rust,compile_fail
441 /// #![deny(missing_docs)]
449 /// This lint is intended to ensure that a library is well-documented.
450 /// Items without documentation can be difficult for users to understand
451 /// how to use properly.
453 /// This lint is "allow" by default because it can be noisy, and not all
454 /// projects may want to enforce everything to be documented.
457 "detects missing documentation for public members",
458 report_in_external_macro
461 pub struct MissingDoc
;
463 impl_lint_pass
!(MissingDoc
=> [MISSING_DOCS
]);
465 fn has_doc(attr
: &ast
::Attribute
) -> bool
{
466 if attr
.is_doc_comment() {
470 if !attr
.has_name(sym
::doc
) {
474 if attr
.value_str().is_some() {
478 if let Some(list
) = attr
.meta_item_list() {
480 if meta
.has_name(sym
::hidden
) {
490 fn check_missing_docs_attrs(
492 cx
: &LateContext
<'_
>,
494 article
: &'
static str,
497 // If we're building a test harness, then warning about
498 // documentation is probably not really relevant right now.
499 if cx
.sess().opts
.test
{
503 // Only check publicly-visible items, using the result from the privacy pass.
504 // It's an option so the crate root can also use this function (it doesn't
506 if def_id
!= CRATE_DEF_ID
{
507 if !cx
.effective_visibilities
.is_exported(def_id
) {
512 let attrs
= cx
.tcx
.hir().attrs(cx
.tcx
.hir().local_def_id_to_hir_id(def_id
));
513 let has_doc
= attrs
.iter().any(has_doc
);
515 cx
.emit_spanned_lint(
517 cx
.tcx
.def_span(def_id
),
518 BuiltinMissingDoc { article, desc }
,
524 impl<'tcx
> LateLintPass
<'tcx
> for MissingDoc
{
525 fn check_crate(&mut self, cx
: &LateContext
<'_
>) {
526 self.check_missing_docs_attrs(cx
, CRATE_DEF_ID
, "the", "crate");
529 fn check_item(&mut self, cx
: &LateContext
<'_
>, it
: &hir
::Item
<'_
>) {
530 // Previously the Impl and Use types have been excluded from missing docs,
531 // so we will continue to exclude them for compatibility.
533 // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
534 if let hir
::ItemKind
::Impl(..) | hir
::ItemKind
::Use(..) | hir
::ItemKind
::ExternCrate(_
) =
540 let (article
, desc
) = cx
.tcx
.article_and_description(it
.owner_id
.to_def_id());
541 self.check_missing_docs_attrs(cx
, it
.owner_id
.def_id
, article
, desc
);
544 fn check_trait_item(&mut self, cx
: &LateContext
<'_
>, trait_item
: &hir
::TraitItem
<'_
>) {
545 let (article
, desc
) = cx
.tcx
.article_and_description(trait_item
.owner_id
.to_def_id());
547 self.check_missing_docs_attrs(cx
, trait_item
.owner_id
.def_id
, article
, desc
);
550 fn check_impl_item(&mut self, cx
: &LateContext
<'_
>, impl_item
: &hir
::ImplItem
<'_
>) {
551 let context
= method_context(cx
, impl_item
.owner_id
.def_id
);
554 // If the method is an impl for a trait, don't doc.
555 MethodLateContext
::TraitImpl
=> return,
556 MethodLateContext
::TraitAutoImpl
=> {}
557 // If the method is an impl for an item with docs_hidden, don't doc.
558 MethodLateContext
::PlainImpl
=> {
559 let parent
= cx
.tcx
.hir().get_parent_item(impl_item
.hir_id());
560 let impl_ty
= cx
.tcx
.type_of(parent
).instantiate_identity();
561 let outerdef
= match impl_ty
.kind() {
562 ty
::Adt(def
, _
) => Some(def
.did()),
563 ty
::Foreign(def_id
) => Some(*def_id
),
566 let is_hidden
= match outerdef
{
567 Some(id
) => cx
.tcx
.is_doc_hidden(id
),
576 let (article
, desc
) = cx
.tcx
.article_and_description(impl_item
.owner_id
.to_def_id());
577 self.check_missing_docs_attrs(cx
, impl_item
.owner_id
.def_id
, article
, desc
);
580 fn check_foreign_item(&mut self, cx
: &LateContext
<'_
>, foreign_item
: &hir
::ForeignItem
<'_
>) {
581 let (article
, desc
) = cx
.tcx
.article_and_description(foreign_item
.owner_id
.to_def_id());
582 self.check_missing_docs_attrs(cx
, foreign_item
.owner_id
.def_id
, article
, desc
);
585 fn check_field_def(&mut self, cx
: &LateContext
<'_
>, sf
: &hir
::FieldDef
<'_
>) {
586 if !sf
.is_positional() {
587 self.check_missing_docs_attrs(cx
, sf
.def_id
, "a", "struct field")
591 fn check_variant(&mut self, cx
: &LateContext
<'_
>, v
: &hir
::Variant
<'_
>) {
592 self.check_missing_docs_attrs(cx
, v
.def_id
, "a", "variant");
597 /// The `missing_copy_implementations` lint detects potentially-forgotten
598 /// implementations of [`Copy`] for public types.
600 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
604 /// ```rust,compile_fail
605 /// #![deny(missing_copy_implementations)]
616 /// Historically (before 1.0), types were automatically marked as `Copy`
617 /// if possible. This was changed so that it required an explicit opt-in
618 /// by implementing the `Copy` trait. As part of this change, a lint was
619 /// added to alert if a copyable type was not marked `Copy`.
621 /// This lint is "allow" by default because this code isn't bad; it is
622 /// common to write newtypes like this specifically so that a `Copy` type
623 /// is no longer `Copy`. `Copy` types can result in unintended copies of
624 /// large data which can impact performance.
625 pub MISSING_COPY_IMPLEMENTATIONS
,
627 "detects potentially-forgotten implementations of `Copy`"
630 declare_lint_pass
!(MissingCopyImplementations
=> [MISSING_COPY_IMPLEMENTATIONS
]);
632 impl<'tcx
> LateLintPass
<'tcx
> for MissingCopyImplementations
{
633 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &hir
::Item
<'_
>) {
634 if !cx
.effective_visibilities
.is_reachable(item
.owner_id
.def_id
) {
637 let (def
, ty
) = match item
.kind
{
638 hir
::ItemKind
::Struct(_
, ref ast_generics
) => {
639 if !ast_generics
.params
.is_empty() {
642 let def
= cx
.tcx
.adt_def(item
.owner_id
);
643 (def
, Ty
::new_adt(cx
.tcx
, def
, ty
::List
::empty()))
645 hir
::ItemKind
::Union(_
, ref ast_generics
) => {
646 if !ast_generics
.params
.is_empty() {
649 let def
= cx
.tcx
.adt_def(item
.owner_id
);
650 (def
, Ty
::new_adt(cx
.tcx
, def
, ty
::List
::empty()))
652 hir
::ItemKind
::Enum(_
, ref ast_generics
) => {
653 if !ast_generics
.params
.is_empty() {
656 let def
= cx
.tcx
.adt_def(item
.owner_id
);
657 (def
, Ty
::new_adt(cx
.tcx
, def
, ty
::List
::empty()))
661 if def
.has_dtor(cx
.tcx
) {
665 // If the type contains a raw pointer, it may represent something like a handle,
666 // and recommending Copy might be a bad idea.
667 for field
in def
.all_fields() {
669 if cx
.tcx
.type_of(did
).instantiate_identity().is_unsafe_ptr() {
673 let param_env
= ty
::ParamEnv
::empty();
674 if ty
.is_copy_modulo_regions(cx
.tcx
, param_env
) {
677 if type_implements_negative_copy_modulo_regions(cx
.tcx
, ty
, param_env
) {
680 if def
.is_variant_list_non_exhaustive()
681 || def
.variants().iter().any(|variant
| variant
.is_field_list_non_exhaustive())
686 // We shouldn't recommend implementing `Copy` on stateful things,
687 // such as iterators.
688 if let Some(iter_trait
) = cx
.tcx
.get_diagnostic_item(sym
::Iterator
)
693 .type_implements_trait(iter_trait
, [ty
], param_env
)
694 .must_apply_modulo_regions()
699 // Default value of clippy::trivially_copy_pass_by_ref
700 const MAX_SIZE
: u64 = 256;
702 if let Some(size
) = cx
.layout_of(ty
).ok().map(|l
| l
.size
.bytes()) {
708 if type_allowed_to_implement_copy(
712 traits
::ObligationCause
::misc(item
.span
, item
.owner_id
.def_id
),
716 cx
.emit_spanned_lint(MISSING_COPY_IMPLEMENTATIONS
, item
.span
, BuiltinMissingCopyImpl
);
721 /// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.
722 fn type_implements_negative_copy_modulo_regions
<'tcx
>(
725 param_env
: ty
::ParamEnv
<'tcx
>,
727 let trait_ref
= ty
::TraitRef
::new(tcx
, tcx
.require_lang_item(hir
::LangItem
::Copy
, None
), [ty
]);
728 let pred
= ty
::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative }
;
729 let obligation
= traits
::Obligation
{
730 cause
: traits
::ObligationCause
::dummy(),
733 predicate
: ty
::Binder
::dummy(pred
).to_predicate(tcx
),
736 tcx
.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation
)
740 /// The `missing_debug_implementations` lint detects missing
741 /// implementations of [`fmt::Debug`] for public types.
743 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
747 /// ```rust,compile_fail
748 /// #![deny(missing_debug_implementations)]
757 /// Having a `Debug` implementation on all types can assist with
758 /// debugging, as it provides a convenient way to format and display a
759 /// value. Using the `#[derive(Debug)]` attribute will automatically
760 /// generate a typical implementation, or a custom implementation can be
761 /// added by manually implementing the `Debug` trait.
763 /// This lint is "allow" by default because adding `Debug` to all types can
764 /// have a negative impact on compile time and code size. It also requires
765 /// boilerplate to be added to every type, which can be an impediment.
766 MISSING_DEBUG_IMPLEMENTATIONS
,
768 "detects missing implementations of Debug"
772 pub(crate) struct MissingDebugImplementations
;
774 impl_lint_pass
!(MissingDebugImplementations
=> [MISSING_DEBUG_IMPLEMENTATIONS
]);
776 impl<'tcx
> LateLintPass
<'tcx
> for MissingDebugImplementations
{
777 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &hir
::Item
<'_
>) {
778 if !cx
.effective_visibilities
.is_reachable(item
.owner_id
.def_id
) {
783 hir
::ItemKind
::Struct(..) | hir
::ItemKind
::Union(..) | hir
::ItemKind
::Enum(..) => {}
787 // Avoid listing trait impls if the trait is allowed.
788 let (level
, _
) = cx
.tcx
.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS
, item
.hir_id());
789 if level
== Level
::Allow
{
793 let Some(debug
) = cx
.tcx
.get_diagnostic_item(sym
::Debug
) else { return }
;
797 .non_blanket_impls_for_ty(debug
, cx
.tcx
.type_of(item
.owner_id
).instantiate_identity())
801 cx
.emit_spanned_lint(
802 MISSING_DEBUG_IMPLEMENTATIONS
,
804 BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug }
,
811 /// The `anonymous_parameters` lint detects anonymous parameters in trait
816 /// ```rust,edition2015,compile_fail
817 /// #![deny(anonymous_parameters)]
829 /// This syntax is mostly a historical accident, and can be worked around
830 /// quite easily by adding an `_` pattern or a descriptive identifier:
834 /// fn foo(_: usize);
838 /// This syntax is now a hard error in the 2018 edition. In the 2015
839 /// edition, this lint is "warn" by default. This lint
840 /// enables the [`cargo fix`] tool with the `--edition` flag to
841 /// automatically transition old code from the 2015 edition to 2018. The
842 /// tool will run this lint and automatically apply the
843 /// suggested fix from the compiler (which is to add `_` to each
844 /// parameter). This provides a completely automated way to update old
845 /// code for a new edition. See [issue #41686] for more details.
847 /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
848 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
849 pub ANONYMOUS_PARAMETERS
,
851 "detects anonymous parameters",
852 @future_incompatible
= FutureIncompatibleInfo
{
853 reason
: FutureIncompatibilityReason
::EditionError(Edition
::Edition2018
),
854 reference
: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
859 /// Checks for use of anonymous parameters (RFC 1685).
860 AnonymousParameters
=> [ANONYMOUS_PARAMETERS
]
863 impl EarlyLintPass
for AnonymousParameters
{
864 fn check_trait_item(&mut self, cx
: &EarlyContext
<'_
>, it
: &ast
::AssocItem
) {
865 if cx
.sess().edition() != Edition
::Edition2015
{
866 // This is a hard error in future editions; avoid linting and erroring
869 if let ast
::AssocItemKind
::Fn(box Fn { ref sig, .. }
) = it
.kind
{
870 for arg
in sig
.decl
.inputs
.iter() {
871 if let ast
::PatKind
::Ident(_
, ident
, None
) = arg
.pat
.kind
{
872 if ident
.name
== kw
::Empty
{
873 let ty_snip
= cx
.sess().source_map().span_to_snippet(arg
.ty
.span
);
875 let (ty_snip
, appl
) = if let Ok(ref snip
) = ty_snip
{
876 (snip
.as_str(), Applicability
::MachineApplicable
)
878 ("<type>", Applicability
::HasPlaceholders
)
880 cx
.emit_spanned_lint(
881 ANONYMOUS_PARAMETERS
,
883 BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip }
,
892 /// Check for use of attributes which have been deprecated.
894 pub struct DeprecatedAttr
{
895 // This is not free to compute, so we want to keep it around, rather than
896 // compute it for every attribute.
897 depr_attrs
: Vec
<&'
static BuiltinAttribute
>,
900 impl_lint_pass
!(DeprecatedAttr
=> []);
902 impl DeprecatedAttr
{
903 pub fn new() -> DeprecatedAttr
{
904 DeprecatedAttr { depr_attrs: deprecated_attributes() }
908 impl EarlyLintPass
for DeprecatedAttr
{
909 fn check_attribute(&mut self, cx
: &EarlyContext
<'_
>, attr
: &ast
::Attribute
) {
910 for BuiltinAttribute { name, gate, .. }
in &self.depr_attrs
{
911 if attr
.ident().map(|ident
| ident
.name
) == Some(*name
) {
912 if let &AttributeGate
::Gated(
913 Stability
::Deprecated(link
, suggestion
),
919 let suggestion
= match suggestion
{
921 BuiltinDeprecatedAttrLinkSuggestion
::Msg { suggestion: attr.span, msg }
924 BuiltinDeprecatedAttrLinkSuggestion
::Default { suggestion: attr.span }
927 cx
.emit_spanned_lint(
930 BuiltinDeprecatedAttrLink { name, reason, link, suggestion }
,
936 if attr
.has_name(sym
::no_start
) || attr
.has_name(sym
::crate_id
) {
937 cx
.emit_spanned_lint(
940 BuiltinDeprecatedAttrUsed
{
941 name
: pprust
::path_to_string(&attr
.get_normal_item().path
),
942 suggestion
: attr
.span
,
949 fn warn_if_doc(cx
: &EarlyContext
<'_
>, node_span
: Span
, node_kind
: &str, attrs
: &[ast
::Attribute
]) {
950 use rustc_ast
::token
::CommentKind
;
952 let mut attrs
= attrs
.iter().peekable();
954 // Accumulate a single span for sugared doc comments.
955 let mut sugared_span
: Option
<Span
> = None
;
957 while let Some(attr
) = attrs
.next() {
958 let is_doc_comment
= attr
.is_doc_comment();
961 Some(sugared_span
.map_or(attr
.span
, |span
| span
.with_hi(attr
.span
.hi())));
964 if attrs
.peek().is_some_and(|next_attr
| next_attr
.is_doc_comment()) {
968 let span
= sugared_span
.take().unwrap_or(attr
.span
);
970 if is_doc_comment
|| attr
.has_name(sym
::doc
) {
971 let sub
= match attr
.kind
{
972 AttrKind
::DocComment(CommentKind
::Line
, _
) | AttrKind
::Normal(..) => {
973 BuiltinUnusedDocCommentSub
::PlainHelp
975 AttrKind
::DocComment(CommentKind
::Block
, _
) => {
976 BuiltinUnusedDocCommentSub
::BlockHelp
979 cx
.emit_spanned_lint(
982 BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub }
,
988 impl EarlyLintPass
for UnusedDocComment
{
989 fn check_stmt(&mut self, cx
: &EarlyContext
<'_
>, stmt
: &ast
::Stmt
) {
990 let kind
= match stmt
.kind
{
991 ast
::StmtKind
::Local(..) => "statements",
992 // Disabled pending discussion in #78306
993 ast
::StmtKind
::Item(..) => return,
994 // expressions will be reported by `check_expr`.
996 | ast
::StmtKind
::Semi(_
)
997 | ast
::StmtKind
::Expr(_
)
998 | ast
::StmtKind
::MacCall(_
) => return,
1001 warn_if_doc(cx
, stmt
.span
, kind
, stmt
.kind
.attrs());
1004 fn check_arm(&mut self, cx
: &EarlyContext
<'_
>, arm
: &ast
::Arm
) {
1005 let arm_span
= arm
.pat
.span
.with_hi(arm
.body
.span
.hi());
1006 warn_if_doc(cx
, arm_span
, "match arms", &arm
.attrs
);
1009 fn check_pat(&mut self, cx
: &EarlyContext
<'_
>, pat
: &ast
::Pat
) {
1010 if let ast
::PatKind
::Struct(_
, _
, fields
, _
) = &pat
.kind
{
1011 for field
in fields
{
1012 warn_if_doc(cx
, field
.span
, "pattern fields", &field
.attrs
);
1017 fn check_expr(&mut self, cx
: &EarlyContext
<'_
>, expr
: &ast
::Expr
) {
1018 warn_if_doc(cx
, expr
.span
, "expressions", &expr
.attrs
);
1020 if let ExprKind
::Struct(s
) = &expr
.kind
{
1021 for field
in &s
.fields
{
1022 warn_if_doc(cx
, field
.span
, "expression fields", &field
.attrs
);
1027 fn check_generic_param(&mut self, cx
: &EarlyContext
<'_
>, param
: &ast
::GenericParam
) {
1028 warn_if_doc(cx
, param
.ident
.span
, "generic parameters", ¶m
.attrs
);
1031 fn check_block(&mut self, cx
: &EarlyContext
<'_
>, block
: &ast
::Block
) {
1032 warn_if_doc(cx
, block
.span
, "blocks", &block
.attrs());
1035 fn check_item(&mut self, cx
: &EarlyContext
<'_
>, item
: &ast
::Item
) {
1036 if let ast
::ItemKind
::ForeignMod(_
) = item
.kind
{
1037 warn_if_doc(cx
, item
.span
, "extern blocks", &item
.attrs
);
1043 /// The `no_mangle_const_items` lint detects any `const` items with the
1044 /// [`no_mangle` attribute].
1046 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1050 /// ```rust,compile_fail
1052 /// const FOO: i32 = 5;
1059 /// Constants do not have their symbols exported, and therefore, this
1060 /// probably means you meant to use a [`static`], not a [`const`].
1062 /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
1063 /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
1064 NO_MANGLE_CONST_ITEMS
,
1066 "const items will not have their symbols exported"
1070 /// The `no_mangle_generic_items` lint detects generic items that must be
1077 /// fn foo<T>(t: T) {
1086 /// A function with generics must have its symbol mangled to accommodate
1087 /// the generic parameter. The [`no_mangle` attribute] has no effect in
1088 /// this situation, and should be removed.
1090 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1091 NO_MANGLE_GENERIC_ITEMS
,
1093 "generic items must be mangled"
1096 declare_lint_pass
!(InvalidNoMangleItems
=> [NO_MANGLE_CONST_ITEMS
, NO_MANGLE_GENERIC_ITEMS
]);
1098 impl<'tcx
> LateLintPass
<'tcx
> for InvalidNoMangleItems
{
1099 fn check_item(&mut self, cx
: &LateContext
<'_
>, it
: &hir
::Item
<'_
>) {
1100 let attrs
= cx
.tcx
.hir().attrs(it
.hir_id());
1101 let check_no_mangle_on_generic_fn
= |no_mangle_attr
: &ast
::Attribute
,
1102 impl_generics
: Option
<&hir
::Generics
<'_
>>,
1103 generics
: &hir
::Generics
<'_
>,
1106 generics
.params
.iter().chain(impl_generics
.map(|g
| g
.params
).into_iter().flatten())
1109 GenericParamKind
::Lifetime { .. }
=> {}
1110 GenericParamKind
::Type { .. }
| GenericParamKind
::Const { .. }
=> {
1111 cx
.emit_spanned_lint(
1112 NO_MANGLE_GENERIC_ITEMS
,
1114 BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }
,
1122 hir
::ItemKind
::Fn(.., ref generics
, _
) => {
1123 if let Some(no_mangle_attr
) = attr
::find_by_name(attrs
, sym
::no_mangle
) {
1124 check_no_mangle_on_generic_fn(no_mangle_attr
, None
, generics
, it
.span
);
1127 hir
::ItemKind
::Const(..) => {
1128 if attr
::contains_name(attrs
, sym
::no_mangle
) {
1129 // account for "pub const" (#45562)
1134 .span_to_snippet(it
.span
)
1135 .map(|snippet
| snippet
.find("const").unwrap_or(0))
1136 .unwrap_or(0) as u32;
1137 // `const` is 5 chars
1138 let suggestion
= it
.span
.with_hi(BytePos(it
.span
.lo().0 + start
+ 5));
1140 // Const items do not refer to a particular location in memory, and therefore
1141 // don't have anything to attach a symbol to
1142 cx
.emit_spanned_lint(
1143 NO_MANGLE_CONST_ITEMS
,
1145 BuiltinConstNoMangle { suggestion }
,
1149 hir
::ItemKind
::Impl(hir
::Impl { generics, items, .. }
) => {
1151 if let hir
::AssocItemKind
::Fn { .. }
= it
.kind
{
1152 if let Some(no_mangle_attr
) =
1153 attr
::find_by_name(cx
.tcx
.hir().attrs(it
.id
.hir_id()), sym
::no_mangle
)
1155 check_no_mangle_on_generic_fn(
1158 cx
.tcx
.hir().get_generics(it
.id
.owner_id
.def_id
).unwrap(),
1171 /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1172 /// T` because it is [undefined behavior].
1174 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1178 /// ```rust,compile_fail
1180 /// let y = std::mem::transmute::<&i32, &mut i32>(&5);
1188 /// Certain assumptions are made about aliasing of data, and this transmute
1189 /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1191 /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1194 "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1197 declare_lint_pass
!(MutableTransmutes
=> [MUTABLE_TRANSMUTES
]);
1199 impl<'tcx
> LateLintPass
<'tcx
> for MutableTransmutes
{
1200 fn check_expr(&mut self, cx
: &LateContext
<'_
>, expr
: &hir
::Expr
<'_
>) {
1201 if let Some((&ty
::Ref(_
, _
, from_mutbl
), &ty
::Ref(_
, _
, to_mutbl
))) =
1202 get_transmute_from_to(cx
, expr
).map(|(ty1
, ty2
)| (ty1
.kind(), ty2
.kind()))
1204 if from_mutbl
< to_mutbl
{
1205 cx
.emit_spanned_lint(MUTABLE_TRANSMUTES
, expr
.span
, BuiltinMutablesTransmutes
);
1209 fn get_transmute_from_to
<'tcx
>(
1210 cx
: &LateContext
<'tcx
>,
1211 expr
: &hir
::Expr
<'_
>,
1212 ) -> Option
<(Ty
<'tcx
>, Ty
<'tcx
>)> {
1213 let def
= if let hir
::ExprKind
::Path(ref qpath
) = expr
.kind
{
1214 cx
.qpath_res(qpath
, expr
.hir_id
)
1218 if let Res
::Def(DefKind
::Fn
, did
) = def
{
1219 if !def_id_is_transmute(cx
, did
) {
1222 let sig
= cx
.typeck_results().node_type(expr
.hir_id
).fn_sig(cx
.tcx
);
1223 let from
= sig
.inputs().skip_binder()[0];
1224 let to
= sig
.output().skip_binder();
1225 return Some((from
, to
));
1230 fn def_id_is_transmute(cx
: &LateContext
<'_
>, def_id
: DefId
) -> bool
{
1231 cx
.tcx
.is_intrinsic(def_id
) && cx
.tcx
.item_name(def_id
) == sym
::transmute
1237 /// The `unstable_features` is deprecated and should no longer be used.
1240 "enabling unstable features (deprecated. do not use)"
1244 /// Forbids using the `#[feature(...)]` attribute
1245 UnstableFeatures
=> [UNSTABLE_FEATURES
]
1248 impl<'tcx
> LateLintPass
<'tcx
> for UnstableFeatures
{
1249 fn check_attribute(&mut self, cx
: &LateContext
<'_
>, attr
: &ast
::Attribute
) {
1250 if attr
.has_name(sym
::feature
) {
1251 if let Some(items
) = attr
.meta_item_list() {
1253 cx
.emit_spanned_lint(UNSTABLE_FEATURES
, item
.span(), BuiltinUnstableFeatures
);
1261 /// The `ungated_async_fn_track_caller` lint warns when the
1262 /// `#[track_caller]` attribute is used on an async function
1263 /// without enabling the corresponding unstable feature flag.
1269 /// async fn foo() {}
1276 /// The attribute must be used in conjunction with the
1277 /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`
1278 /// annotation will function as a no-op.
1280 /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html
1281 UNGATED_ASYNC_FN_TRACK_CALLER
,
1283 "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"
1287 /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to
1289 UngatedAsyncFnTrackCaller
=> [UNGATED_ASYNC_FN_TRACK_CALLER
]
1292 impl<'tcx
> LateLintPass
<'tcx
> for UngatedAsyncFnTrackCaller
{
1295 cx
: &LateContext
<'_
>,
1296 fn_kind
: HirFnKind
<'_
>,
1297 _
: &'tcx FnDecl
<'_
>,
1302 if fn_kind
.asyncness().is_async()
1303 && !cx
.tcx
.features().async_fn_track_caller
1304 // Now, check if the function has the `#[track_caller]` attribute
1305 && let Some(attr
) = cx
.tcx
.get_attr(def_id
, sym
::track_caller
)
1307 cx
.emit_spanned_lint(
1308 UNGATED_ASYNC_FN_TRACK_CALLER
,
1310 BuiltinUngatedAsyncFnTrackCaller
{
1312 parse_sess
: &cx
.tcx
.sess
.parse_sess
,
1320 /// The `unreachable_pub` lint triggers for `pub` items not reachable from
1325 /// ```rust,compile_fail
1326 /// #![deny(unreachable_pub)]
1338 /// The `pub` keyword both expresses an intent for an item to be publicly available, and also
1339 /// signals to the compiler to make the item publicly accessible. The intent can only be
1340 /// satisfied, however, if all items which contain this item are *also* publicly accessible.
1341 /// Thus, this lint serves to identify situations where the intent does not match the reality.
1343 /// If you wish the item to be accessible elsewhere within the crate, but not outside it, the
1344 /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the
1345 /// intent that the item is only visible within its own crate.
1347 /// This lint is "allow" by default because it will trigger for a large
1348 /// amount existing Rust code, and has some false-positives. Eventually it
1349 /// is desired for this to become warn-by-default.
1350 pub UNREACHABLE_PUB
,
1352 "`pub` items not reachable from crate root"
1356 /// Lint for items marked `pub` that aren't reachable from other crates.
1357 UnreachablePub
=> [UNREACHABLE_PUB
]
1360 impl UnreachablePub
{
1363 cx
: &LateContext
<'_
>,
1369 let mut applicability
= Applicability
::MachineApplicable
;
1370 if cx
.tcx
.visibility(def_id
).is_public() && !cx
.effective_visibilities
.is_reachable(def_id
)
1372 if vis_span
.from_expansion() {
1373 applicability
= Applicability
::MaybeIncorrect
;
1375 let def_span
= cx
.tcx
.def_span(def_id
);
1376 cx
.emit_spanned_lint(
1379 BuiltinUnreachablePub
{
1381 suggestion
: (vis_span
, applicability
),
1382 help
: exportable
.then_some(()),
1389 impl<'tcx
> LateLintPass
<'tcx
> for UnreachablePub
{
1390 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &hir
::Item
<'_
>) {
1391 // Do not warn for fake `use` statements.
1392 if let hir
::ItemKind
::Use(_
, hir
::UseKind
::ListStem
) = &item
.kind
{
1395 self.perform_lint(cx
, "item", item
.owner_id
.def_id
, item
.vis_span
, true);
1398 fn check_foreign_item(&mut self, cx
: &LateContext
<'_
>, foreign_item
: &hir
::ForeignItem
<'tcx
>) {
1399 self.perform_lint(cx
, "item", foreign_item
.owner_id
.def_id
, foreign_item
.vis_span
, true);
1402 fn check_field_def(&mut self, cx
: &LateContext
<'_
>, field
: &hir
::FieldDef
<'_
>) {
1403 let map
= cx
.tcx
.hir();
1404 if matches
!(map
.get_parent(field
.hir_id
), Node
::Variant(_
)) {
1407 self.perform_lint(cx
, "field", field
.def_id
, field
.vis_span
, false);
1410 fn check_impl_item(&mut self, cx
: &LateContext
<'_
>, impl_item
: &hir
::ImplItem
<'_
>) {
1411 // Only lint inherent impl items.
1412 if cx
.tcx
.associated_item(impl_item
.owner_id
).trait_item_def_id
.is_none() {
1413 self.perform_lint(cx
, "item", impl_item
.owner_id
.def_id
, impl_item
.vis_span
, false);
1419 /// The `type_alias_bounds` lint detects bounds in type aliases.
1424 /// type SendVec<T: Send> = Vec<T>;
1431 /// The trait bounds in a type alias are currently ignored, and should not
1432 /// be included to avoid confusion. This was previously allowed
1433 /// unintentionally; this may become a hard error in the future.
1436 "bounds in type aliases are not enforced"
1440 /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1441 /// They are relevant when using associated types, but otherwise neither checked
1442 /// at definition site nor enforced at use site.
1443 TypeAliasBounds
=> [TYPE_ALIAS_BOUNDS
]
1446 impl TypeAliasBounds
{
1447 pub(crate) fn is_type_variable_assoc(qpath
: &hir
::QPath
<'_
>) -> bool
{
1449 hir
::QPath
::TypeRelative(ref ty
, _
) => {
1450 // If this is a type variable, we found a `T::Assoc`.
1452 hir
::TyKind
::Path(hir
::QPath
::Resolved(None
, ref path
)) => {
1453 matches
!(path
.res
, Res
::Def(DefKind
::TyParam
, _
))
1458 hir
::QPath
::Resolved(..) | hir
::QPath
::LangItem(..) => false,
1463 impl<'tcx
> LateLintPass
<'tcx
> for TypeAliasBounds
{
1464 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &hir
::Item
<'_
>) {
1465 let hir
::ItemKind
::TyAlias(hir_ty
, type_alias_generics
) = &item
.kind
else { return }
;
1467 // Bounds of lazy type aliases and TAITs are respected.
1468 if cx
.tcx
.type_alias_is_lazy(item
.owner_id
) {
1472 let ty
= cx
.tcx
.type_of(item
.owner_id
).skip_binder();
1473 if ty
.has_inherent_projections() {
1474 // Bounds of type aliases that contain opaque types or inherent projections are respected.
1475 // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`.
1479 // There must not be a where clause
1480 if type_alias_generics
.predicates
.is_empty() {
1484 let mut where_spans
= Vec
::new();
1485 let mut inline_spans
= Vec
::new();
1486 let mut inline_sugg
= Vec
::new();
1487 for p
in type_alias_generics
.predicates
{
1488 let span
= p
.span();
1489 if p
.in_where_clause() {
1490 where_spans
.push(span
);
1492 for b
in p
.bounds() {
1493 inline_spans
.push(b
.span());
1495 inline_sugg
.push((span
, String
::new()));
1499 let mut suggested_changing_assoc_types
= false;
1500 if !where_spans
.is_empty() {
1501 let sub
= (!suggested_changing_assoc_types
).then(|| {
1502 suggested_changing_assoc_types
= true;
1503 SuggestChangingAssocTypes { ty: hir_ty }
1505 cx
.emit_spanned_lint(
1508 BuiltinTypeAliasWhereClause
{
1509 suggestion
: type_alias_generics
.where_clause_span
,
1515 if !inline_spans
.is_empty() {
1516 let suggestion
= BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg }
;
1517 let sub
= (!suggested_changing_assoc_types
).then(|| {
1518 suggested_changing_assoc_types
= true;
1519 SuggestChangingAssocTypes { ty: hir_ty }
1521 cx
.emit_spanned_lint(
1524 BuiltinTypeAliasGenericBounds { suggestion, sub }
,
1531 /// Lint constants that are erroneous.
1532 /// Without this lint, we might not get any diagnostic if the constant is
1533 /// unused within this crate, even though downstream crates can't use it
1534 /// without producing an error.
1535 UnusedBrokenConst
=> []
1538 impl<'tcx
> LateLintPass
<'tcx
> for UnusedBrokenConst
{
1539 fn check_item(&mut self, cx
: &LateContext
<'_
>, it
: &hir
::Item
<'_
>) {
1541 hir
::ItemKind
::Const(_
, _
, body_id
) => {
1542 let def_id
= cx
.tcx
.hir().body_owner_def_id(body_id
).to_def_id();
1543 // trigger the query once for all constants since that will already report the errors
1544 // FIXME(generic_const_items): Does this work properly with generic const items?
1545 cx
.tcx
.ensure().const_eval_poly(def_id
);
1547 hir
::ItemKind
::Static(_
, _
, body_id
) => {
1548 let def_id
= cx
.tcx
.hir().body_owner_def_id(body_id
).to_def_id();
1549 cx
.tcx
.ensure().eval_static_initializer(def_id
);
1557 /// The `trivial_bounds` lint detects trait bounds that don't depend on
1558 /// any type parameters.
1563 /// #![feature(trivial_bounds)]
1564 /// pub struct A where i32: Copy;
1571 /// Usually you would not write a trait bound that you know is always
1572 /// true, or never true. However, when using macros, the macro may not
1573 /// know whether or not the constraint would hold or not at the time when
1574 /// generating the code. Currently, the compiler does not alert you if the
1575 /// constraint is always true, and generates an error if it is never true.
1576 /// The `trivial_bounds` feature changes this to be a warning in both
1577 /// cases, giving macros more freedom and flexibility to generate code,
1578 /// while still providing a signal when writing non-macro code that
1579 /// something is amiss.
1581 /// See [RFC 2056] for more details. This feature is currently only
1582 /// available on the nightly channel, see [tracking issue #48214].
1584 /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1585 /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1588 "these bounds don't depend on an type parameters"
1592 /// Lint for trait and lifetime bounds that don't depend on type parameters
1593 /// which either do nothing, or stop the item from being used.
1594 TrivialConstraints
=> [TRIVIAL_BOUNDS
]
1597 impl<'tcx
> LateLintPass
<'tcx
> for TrivialConstraints
{
1598 fn check_item(&mut self, cx
: &LateContext
<'tcx
>, item
: &'tcx hir
::Item
<'tcx
>) {
1599 use rustc_middle
::ty
::ClauseKind
;
1601 if cx
.tcx
.features().trivial_bounds
{
1602 let predicates
= cx
.tcx
.predicates_of(item
.owner_id
);
1603 for &(predicate
, span
) in predicates
.predicates
{
1604 let predicate_kind_name
= match predicate
.kind().skip_binder() {
1605 ClauseKind
::Trait(..) => "trait",
1606 ClauseKind
::TypeOutlives(..) |
1607 ClauseKind
::RegionOutlives(..) => "lifetime",
1609 // `ConstArgHasType` is never global as `ct` is always a param
1610 ClauseKind
::ConstArgHasType(..)
1611 // Ignore projections, as they can only be global
1612 // if the trait bound is global
1613 | ClauseKind
::Projection(..)
1614 // Ignore bounds that a user can't type
1615 | ClauseKind
::WellFormed(..)
1616 // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
1617 | ClauseKind
::ConstEvaluatable(..) => continue,
1619 if predicate
.is_global() {
1620 cx
.emit_spanned_lint(
1623 BuiltinTrivialBounds { predicate_kind_name, predicate }
,
1632 /// Does nothing as a lint pass, but registers some `Lint`s
1633 /// which are used by other parts of the compiler.
1637 NON_SHORTHAND_FIELD_PATTERNS
,
1640 MISSING_COPY_IMPLEMENTATIONS
,
1641 MISSING_DEBUG_IMPLEMENTATIONS
,
1642 ANONYMOUS_PARAMETERS
,
1643 UNUSED_DOC_COMMENTS
,
1644 NO_MANGLE_CONST_ITEMS
,
1645 NO_MANGLE_GENERIC_ITEMS
,
1655 /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1656 /// pattern], which is deprecated.
1658 /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1662 /// ```rust,edition2018
1674 /// The `...` range pattern syntax was changed to `..=` to avoid potential
1675 /// confusion with the [`..` range expression]. Use the new form instead.
1677 /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1678 pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS
,
1680 "`...` range patterns are deprecated",
1681 @future_incompatible
= FutureIncompatibleInfo
{
1682 reason
: FutureIncompatibilityReason
::EditionError(Edition
::Edition2021
),
1683 reference
: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1688 pub struct EllipsisInclusiveRangePatterns
{
1689 /// If `Some(_)`, suppress all subsequent pattern
1690 /// warnings for better diagnostics.
1691 node_id
: Option
<ast
::NodeId
>,
1694 impl_lint_pass
!(EllipsisInclusiveRangePatterns
=> [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS
]);
1696 impl EarlyLintPass
for EllipsisInclusiveRangePatterns
{
1697 fn check_pat(&mut self, cx
: &EarlyContext
<'_
>, pat
: &ast
::Pat
) {
1698 if self.node_id
.is_some() {
1699 // Don't recursively warn about patterns inside range endpoints.
1703 use self::ast
::{PatKind, RangeSyntax::DotDotDot}
;
1705 /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1706 /// corresponding to the ellipsis.
1707 fn matches_ellipsis_pat(pat
: &ast
::Pat
) -> Option
<(Option
<&Expr
>, &Expr
, Span
)> {
1712 Spanned { span, node: RangeEnd::Included(DotDotDot) }
,
1713 ) => Some((a
.as_deref(), b
, *span
)),
1718 let (parentheses
, endpoints
) = match &pat
.kind
{
1719 PatKind
::Ref(subpat
, _
) => (true, matches_ellipsis_pat(&subpat
)),
1720 _
=> (false, matches_ellipsis_pat(pat
)),
1723 if let Some((start
, end
, join
)) = endpoints
{
1725 self.node_id
= Some(pat
.id
);
1726 let end
= expr_to_string(&end
);
1727 let replace
= match start
{
1728 Some(start
) => format
!("&({}..={})", expr_to_string(&start
), end
),
1729 None
=> format
!("&(..={end})"),
1731 if join
.edition() >= Edition
::Edition2021
{
1732 cx
.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns
{
1734 suggestion
: pat
.span
,
1738 cx
.emit_spanned_lint(
1739 ELLIPSIS_INCLUSIVE_RANGE_PATTERNS
,
1741 BuiltinEllipsisInclusiveRangePatternsLint
::Parenthesise
{
1742 suggestion
: pat
.span
,
1748 let replace
= "..=";
1749 if join
.edition() >= Edition
::Edition2021
{
1750 cx
.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns
{
1753 replace
: replace
.to_string(),
1756 cx
.emit_spanned_lint(
1757 ELLIPSIS_INCLUSIVE_RANGE_PATTERNS
,
1759 BuiltinEllipsisInclusiveRangePatternsLint
::NonParenthesise
{
1768 fn check_pat_post(&mut self, _cx
: &EarlyContext
<'_
>, pat
: &ast
::Pat
) {
1769 if let Some(node_id
) = self.node_id
{
1770 if pat
.id
== node_id
{
1778 /// The `keyword_idents` lint detects edition keywords being used as an
1783 /// ```rust,edition2015,compile_fail
1784 /// #![deny(keyword_idents)]
1793 /// Rust [editions] allow the language to evolve without breaking
1794 /// backwards compatibility. This lint catches code that uses new keywords
1795 /// that are added to the language that are used as identifiers (such as a
1796 /// variable name, function name, etc.). If you switch the compiler to a
1797 /// new edition without updating the code, then it will fail to compile if
1798 /// you are using a new keyword as an identifier.
1800 /// You can manually change the identifiers to a non-keyword, or use a
1801 /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1803 /// This lint solves the problem automatically. It is "allow" by default
1804 /// because the code is perfectly valid in older editions. The [`cargo
1805 /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1806 /// and automatically apply the suggested fix from the compiler (which is
1807 /// to use a raw identifier). This provides a completely automated way to
1808 /// update old code for a new edition.
1810 /// [editions]: https://doc.rust-lang.org/edition-guide/
1811 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1812 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1815 "detects edition keywords being used as an identifier",
1816 @future_incompatible
= FutureIncompatibleInfo
{
1817 reason
: FutureIncompatibilityReason
::EditionError(Edition
::Edition2018
),
1818 reference
: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1823 /// Check for uses of edition keywords used as an identifier.
1824 KeywordIdents
=> [KEYWORD_IDENTS
]
1827 struct UnderMacro(bool
);
1829 impl KeywordIdents
{
1830 fn check_tokens(&mut self, cx
: &EarlyContext
<'_
>, tokens
: &TokenStream
) {
1831 for tt
in tokens
.trees() {
1833 // Only report non-raw idents.
1834 TokenTree
::Token(token
, _
) => {
1835 if let Some((ident
, false)) = token
.ident() {
1836 self.check_ident_token(cx
, UnderMacro(true), ident
);
1839 TokenTree
::Delimited(_
, _
, tts
) => self.check_tokens(cx
, tts
),
1844 fn check_ident_token(
1846 cx
: &EarlyContext
<'_
>,
1847 UnderMacro(under_macro
): UnderMacro
,
1850 let next_edition
= match cx
.sess().edition() {
1851 Edition
::Edition2015
=> {
1853 kw
::Async
| kw
::Await
| kw
::Try
=> Edition
::Edition2018
,
1855 // rust-lang/rust#56327: Conservatively do not
1856 // attempt to report occurrences of `dyn` within
1857 // macro definitions or invocations, because `dyn`
1858 // can legitimately occur as a contextual keyword
1859 // in 2015 code denoting its 2018 meaning, and we
1860 // do not want rustfix to inject bugs into working
1861 // code by rewriting such occurrences.
1863 // But if we see `dyn` outside of a macro, we know
1864 // its precise role in the parsed AST and thus are
1865 // assured this is truly an attempt to use it as
1867 kw
::Dyn
if !under_macro
=> Edition
::Edition2018
,
1873 // There are no new keywords yet for the 2018 edition and beyond.
1877 // Don't lint `r#foo`.
1878 if cx
.sess().parse_sess
.raw_identifier_spans
.contains(ident
.span
) {
1882 cx
.emit_spanned_lint(
1885 BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span }
,
1890 impl EarlyLintPass
for KeywordIdents
{
1891 fn check_mac_def(&mut self, cx
: &EarlyContext
<'_
>, mac_def
: &ast
::MacroDef
) {
1892 self.check_tokens(cx
, &mac_def
.body
.tokens
);
1894 fn check_mac(&mut self, cx
: &EarlyContext
<'_
>, mac
: &ast
::MacCall
) {
1895 self.check_tokens(cx
, &mac
.args
.tokens
);
1897 fn check_ident(&mut self, cx
: &EarlyContext
<'_
>, ident
: Ident
) {
1898 self.check_ident_token(cx
, UnderMacro(false), ident
);
1902 declare_lint_pass
!(ExplicitOutlivesRequirements
=> [EXPLICIT_OUTLIVES_REQUIREMENTS
]);
1904 impl ExplicitOutlivesRequirements
{
1905 fn lifetimes_outliving_lifetime
<'tcx
>(
1906 inferred_outlives
: &'tcx
[(ty
::Clause
<'tcx
>, Span
)],
1908 ) -> Vec
<ty
::Region
<'tcx
>> {
1911 .filter_map(|(clause
, _
)| match clause
.kind().skip_binder() {
1912 ty
::ClauseKind
::RegionOutlives(ty
::OutlivesPredicate(a
, b
)) => match *a
{
1913 ty
::ReEarlyBound(ebr
) if ebr
.def_id
== def_id
=> Some(b
),
1921 fn lifetimes_outliving_type
<'tcx
>(
1922 inferred_outlives
: &'tcx
[(ty
::Clause
<'tcx
>, Span
)],
1924 ) -> Vec
<ty
::Region
<'tcx
>> {
1927 .filter_map(|(clause
, _
)| match clause
.kind().skip_binder() {
1928 ty
::ClauseKind
::TypeOutlives(ty
::OutlivesPredicate(a
, b
)) => {
1929 a
.is_param(index
).then_some(b
)
1936 fn collect_outlives_bound_spans
<'tcx
>(
1939 bounds
: &hir
::GenericBounds
<'_
>,
1940 inferred_outlives
: &[ty
::Region
<'tcx
>],
1941 predicate_span
: Span
,
1942 ) -> Vec
<(usize, Span
)> {
1943 use rustc_middle
::middle
::resolve_bound_vars
::ResolvedArg
;
1948 .filter_map(|(i
, bound
)| {
1949 let hir
::GenericBound
::Outlives(lifetime
) = bound
else {
1953 let is_inferred
= match tcx
.named_bound_var(lifetime
.hir_id
) {
1954 Some(ResolvedArg
::EarlyBound(def_id
)) => inferred_outlives
1956 .any(|r
| matches
!(**r
, ty
::ReEarlyBound(ebr
) if { ebr.def_id == def_id }
)),
1964 let span
= bound
.span().find_ancestor_inside(predicate_span
)?
;
1965 if in_external_macro(tcx
.sess
, span
) {
1974 fn consolidate_outlives_bound_spans(
1977 bounds
: &hir
::GenericBounds
<'_
>,
1978 bound_spans
: Vec
<(usize, Span
)>,
1980 if bounds
.is_empty() {
1983 if bound_spans
.len() == bounds
.len() {
1984 let (_
, last_bound_span
) = bound_spans
[bound_spans
.len() - 1];
1985 // If all bounds are inferable, we want to delete the colon, so
1986 // start from just after the parameter (span passed as argument)
1987 vec
![lo
.to(last_bound_span
)]
1989 let mut merged
= Vec
::new();
1990 let mut last_merged_i
= None
;
1992 let mut from_start
= true;
1993 for (i
, bound_span
) in bound_spans
{
1994 match last_merged_i
{
1995 // If the first bound is inferable, our span should also eat the leading `+`.
1997 merged
.push(bound_span
.to(bounds
[1].span().shrink_to_lo()));
1998 last_merged_i
= Some(0);
2000 // If consecutive bounds are inferable, merge their spans
2001 Some(h
) if i
== h
+ 1 => {
2002 if let Some(tail
) = merged
.last_mut() {
2003 // Also eat the trailing `+` if the first
2004 // more-than-one bound is inferable
2005 let to_span
= if from_start
&& i
< bounds
.len() {
2006 bounds
[i
+ 1].span().shrink_to_lo()
2010 *tail
= tail
.to(to_span
);
2011 last_merged_i
= Some(i
);
2013 bug
!("another bound-span visited earlier");
2017 // When we find a non-inferable bound, subsequent inferable bounds
2018 // won't be consecutive from the start (and we'll eat the leading
2019 // `+` rather than the trailing one)
2021 merged
.push(bounds
[i
- 1].span().shrink_to_hi().to(bound_span
));
2022 last_merged_i
= Some(i
);
2031 impl<'tcx
> LateLintPass
<'tcx
> for ExplicitOutlivesRequirements
{
2032 fn check_item(&mut self, cx
: &LateContext
<'tcx
>, item
: &'tcx hir
::Item
<'_
>) {
2033 use rustc_middle
::middle
::resolve_bound_vars
::ResolvedArg
;
2035 let def_id
= item
.owner_id
.def_id
;
2036 if let hir
::ItemKind
::Struct(_
, hir_generics
)
2037 | hir
::ItemKind
::Enum(_
, hir_generics
)
2038 | hir
::ItemKind
::Union(_
, hir_generics
) = item
.kind
2040 let inferred_outlives
= cx
.tcx
.inferred_outlives_of(def_id
);
2041 if inferred_outlives
.is_empty() {
2045 let ty_generics
= cx
.tcx
.generics_of(def_id
);
2046 let num_where_predicates
= hir_generics
2049 .filter(|predicate
| predicate
.in_where_clause())
2052 let mut bound_count
= 0;
2053 let mut lint_spans
= Vec
::new();
2054 let mut where_lint_spans
= Vec
::new();
2055 let mut dropped_where_predicate_count
= 0;
2056 for (i
, where_predicate
) in hir_generics
.predicates
.iter().enumerate() {
2057 let (relevant_lifetimes
, bounds
, predicate_span
, in_where_clause
) =
2058 match where_predicate
{
2059 hir
::WherePredicate
::RegionPredicate(predicate
) => {
2060 if let Some(ResolvedArg
::EarlyBound(region_def_id
)) =
2061 cx
.tcx
.named_bound_var(predicate
.lifetime
.hir_id
)
2064 Self::lifetimes_outliving_lifetime(
2070 predicate
.in_where_clause
,
2076 hir
::WherePredicate
::BoundPredicate(predicate
) => {
2077 // FIXME we can also infer bounds on associated types,
2078 // and should check for them here.
2079 match predicate
.bounded_ty
.kind
{
2080 hir
::TyKind
::Path(hir
::QPath
::Resolved(None
, path
)) => {
2081 let Res
::Def(DefKind
::TyParam
, def_id
) = path
.res
else {
2084 let index
= ty_generics
.param_def_id_to_index
[&def_id
];
2086 Self::lifetimes_outliving_type(inferred_outlives
, index
),
2089 predicate
.origin
== PredicateOrigin
::WhereClause
,
2099 if relevant_lifetimes
.is_empty() {
2103 let bound_spans
= self.collect_outlives_bound_spans(
2106 &relevant_lifetimes
,
2109 bound_count
+= bound_spans
.len();
2111 let drop_predicate
= bound_spans
.len() == bounds
.len();
2112 if drop_predicate
&& in_where_clause
{
2113 dropped_where_predicate_count
+= 1;
2117 if !in_where_clause
{
2118 lint_spans
.push(predicate_span
);
2119 } else if predicate_span
.from_expansion() {
2120 // Don't try to extend the span if it comes from a macro expansion.
2121 where_lint_spans
.push(predicate_span
);
2122 } else if i
+ 1 < num_where_predicates
{
2123 // If all the bounds on a predicate were inferable and there are
2124 // further predicates, we want to eat the trailing comma.
2125 let next_predicate_span
= hir_generics
.predicates
[i
+ 1].span();
2126 if next_predicate_span
.from_expansion() {
2127 where_lint_spans
.push(predicate_span
);
2130 .push(predicate_span
.to(next_predicate_span
.shrink_to_lo()));
2133 // Eat the optional trailing comma after the last predicate.
2134 let where_span
= hir_generics
.where_clause_span
;
2135 if where_span
.from_expansion() {
2136 where_lint_spans
.push(predicate_span
);
2138 where_lint_spans
.push(predicate_span
.to(where_span
.shrink_to_hi()));
2142 where_lint_spans
.extend(self.consolidate_outlives_bound_spans(
2143 predicate_span
.shrink_to_lo(),
2150 // If all predicates in where clause are inferable, drop the entire clause
2151 // (including the `where`)
2152 if hir_generics
.has_where_clause_predicates
2153 && dropped_where_predicate_count
== num_where_predicates
2155 let where_span
= hir_generics
.where_clause_span
;
2156 // Extend the where clause back to the closing `>` of the
2157 // generics, except for tuple struct, which have the `where`
2158 // after the fields of the struct.
2159 let full_where_span
=
2160 if let hir
::ItemKind
::Struct(hir
::VariantData
::Tuple(..), _
) = item
.kind
{
2163 hir_generics
.span
.shrink_to_hi().to(where_span
)
2166 // Due to macro expansions, the `full_where_span` might not actually contain all predicates.
2167 if where_lint_spans
.iter().all(|&sp
| full_where_span
.contains(sp
)) {
2168 lint_spans
.push(full_where_span
);
2170 lint_spans
.extend(where_lint_spans
);
2173 lint_spans
.extend(where_lint_spans
);
2176 if !lint_spans
.is_empty() {
2177 // Do not automatically delete outlives requirements from macros.
2178 let applicability
= if lint_spans
.iter().all(|sp
| sp
.can_be_used_for_suggestions())
2180 Applicability
::MachineApplicable
2182 Applicability
::MaybeIncorrect
2185 // Due to macros, there might be several predicates with the same span
2186 // and we only want to suggest removing them once.
2187 lint_spans
.sort_unstable();
2190 cx
.emit_spanned_lint(
2191 EXPLICIT_OUTLIVES_REQUIREMENTS
,
2193 BuiltinExplicitOutlives
{
2195 suggestion
: BuiltinExplicitOutlivesSuggestion
{
2207 /// The `incomplete_features` lint detects unstable features enabled with
2208 /// the [`feature` attribute] that may function improperly in some or all
2211 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2216 /// #![feature(generic_const_exprs)]
2223 /// Although it is encouraged for people to experiment with unstable
2224 /// features, some of them are known to be incomplete or faulty. This lint
2225 /// is a signal that the feature has not yet been finished, and you may
2226 /// experience problems with it.
2227 pub INCOMPLETE_FEATURES
,
2229 "incomplete features that may function improperly in some or all cases"
2233 /// The `internal_features` lint detects unstable features enabled with
2234 /// the [`feature` attribute] that are internal to the compiler or standard
2237 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2242 /// #![feature(rustc_attrs)]
2249 /// These features are an implementation detail of the compiler and standard
2250 /// library and are not supposed to be used in user code.
2251 pub INTERNAL_FEATURES
,
2253 "internal features are not supposed to be used"
2257 /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
2258 IncompleteInternalFeatures
=> [INCOMPLETE_FEATURES
, INTERNAL_FEATURES
]
2261 impl EarlyLintPass
for IncompleteInternalFeatures
{
2262 fn check_crate(&mut self, cx
: &EarlyContext
<'_
>, _
: &ast
::Crate
) {
2263 let features
= cx
.builder
.features();
2265 .declared_lang_features
2267 .map(|(name
, span
, _
)| (name
, span
))
2268 .chain(features
.declared_lib_features
.iter().map(|(name
, span
)| (name
, span
)))
2269 .filter(|(&name
, _
)| features
.incomplete(name
) || features
.internal(name
))
2270 .for_each(|(&name
, &span
)| {
2271 if features
.incomplete(name
) {
2272 let note
= rustc_feature
::find_feature_issue(name
, GateIssue
::Language
)
2273 .map(|n
| BuiltinFeatureIssueNote { n }
);
2275 HAS_MIN_FEATURES
.contains(&name
).then_some(BuiltinIncompleteFeaturesHelp
);
2277 cx
.emit_spanned_lint(
2278 INCOMPLETE_FEATURES
,
2280 BuiltinIncompleteFeatures { name, note, help }
,
2283 cx
.emit_spanned_lint(INTERNAL_FEATURES
, span
, BuiltinInternalFeatures { name }
);
2289 const HAS_MIN_FEATURES
: &[Symbol
] = &[sym
::specialization
];
2292 /// The `invalid_value` lint detects creating a value that is not valid,
2293 /// such as a null reference.
2298 /// # #![allow(unused)]
2300 /// let x: &'static i32 = std::mem::zeroed();
2308 /// In some situations the compiler can detect that the code is creating
2309 /// an invalid value, which should be avoided.
2311 /// In particular, this lint will check for improper use of
2312 /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2313 /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2314 /// lint should provide extra information to indicate what the problem is
2315 /// and a possible solution.
2317 /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2318 /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2319 /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2320 /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2321 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2324 "an invalid value is being created (such as a null reference)"
2327 declare_lint_pass
!(InvalidValue
=> [INVALID_VALUE
]);
2329 /// Information about why a type cannot be initialized this way.
2330 pub struct InitError
{
2331 pub(crate) message
: String
,
2332 /// Spans from struct fields and similar that can be obtained from just the type.
2333 pub(crate) span
: Option
<Span
>,
2334 /// Used to report a trace through adts.
2335 pub(crate) nested
: Option
<Box
<InitError
>>,
2338 fn spanned(self, span
: Span
) -> InitError
{
2339 Self { span: Some(span), ..self }
2342 fn nested(self, nested
: impl Into
<Option
<InitError
>>) -> InitError
{
2343 assert
!(self.nested
.is_none());
2344 Self { nested: nested.into().map(Box::new), ..self }
2348 impl<'a
> From
<&'a
str> for InitError
{
2349 fn from(s
: &'a
str) -> Self {
2353 impl From
<String
> for InitError
{
2354 fn from(message
: String
) -> Self {
2355 Self { message, span: None, nested: None }
2359 impl<'tcx
> LateLintPass
<'tcx
> for InvalidValue
{
2360 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &hir
::Expr
<'_
>) {
2361 #[derive(Debug, Copy, Clone, PartialEq)]
2367 /// Test if this constant is all-0.
2368 fn is_zero(expr
: &hir
::Expr
<'_
>) -> bool
{
2369 use hir
::ExprKind
::*;
2370 use rustc_ast
::LitKind
::*;
2373 if let Int(i
, _
) = lit
.node
{
2379 Tup(tup
) => tup
.iter().all(is_zero
),
2384 /// Determine if this expression is a "dangerous initialization".
2385 fn is_dangerous_init(cx
: &LateContext
<'_
>, expr
: &hir
::Expr
<'_
>) -> Option
<InitKind
> {
2386 if let hir
::ExprKind
::Call(ref path_expr
, ref args
) = expr
.kind
{
2387 // Find calls to `mem::{uninitialized,zeroed}` methods.
2388 if let hir
::ExprKind
::Path(ref qpath
) = path_expr
.kind
{
2389 let def_id
= cx
.qpath_res(qpath
, path_expr
.hir_id
).opt_def_id()?
;
2390 match cx
.tcx
.get_diagnostic_name(def_id
) {
2391 Some(sym
::mem_zeroed
) => return Some(InitKind
::Zeroed
),
2392 Some(sym
::mem_uninitialized
) => return Some(InitKind
::Uninit
),
2393 Some(sym
::transmute
) if is_zero(&args
[0]) => return Some(InitKind
::Zeroed
),
2397 } else if let hir
::ExprKind
::MethodCall(_
, receiver
, ..) = expr
.kind
{
2398 // Find problematic calls to `MaybeUninit::assume_init`.
2399 let def_id
= cx
.typeck_results().type_dependent_def_id(expr
.hir_id
)?
;
2400 if cx
.tcx
.is_diagnostic_item(sym
::assume_init
, def_id
) {
2401 // This is a call to *some* method named `assume_init`.
2402 // See if the `self` parameter is one of the dangerous constructors.
2403 if let hir
::ExprKind
::Call(ref path_expr
, _
) = receiver
.kind
{
2404 if let hir
::ExprKind
::Path(ref qpath
) = path_expr
.kind
{
2405 let def_id
= cx
.qpath_res(qpath
, path_expr
.hir_id
).opt_def_id()?
;
2406 match cx
.tcx
.get_diagnostic_name(def_id
) {
2407 Some(sym
::maybe_uninit_zeroed
) => return Some(InitKind
::Zeroed
),
2408 Some(sym
::maybe_uninit_uninit
) => return Some(InitKind
::Uninit
),
2419 fn variant_find_init_error
<'tcx
>(
2420 cx
: &LateContext
<'tcx
>,
2422 variant
: &VariantDef
,
2423 args
: ty
::GenericArgsRef
<'tcx
>,
2426 ) -> Option
<InitError
> {
2427 let mut field_err
= variant
.fields
.iter().find_map(|field
| {
2428 ty_find_init_error(cx
, field
.ty(cx
.tcx
, args
), init
).map(|mut err
| {
2429 if !field
.did
.is_local() {
2431 } else if err
.span
.is_none() {
2432 err
.span
= Some(cx
.tcx
.def_span(field
.did
));
2433 write
!(&mut err
.message
, " (in this {descr})").unwrap();
2436 InitError
::from(format
!("in this {descr}"))
2437 .spanned(cx
.tcx
.def_span(field
.did
))
2443 // Check if this ADT has a constrained layout (like `NonNull` and friends).
2444 if let Ok(layout
) = cx
.tcx
.layout_of(cx
.param_env
.and(ty
)) {
2445 if let Abi
::Scalar(scalar
) | Abi
::ScalarPair(scalar
, _
) = &layout
.abi
{
2446 let range
= scalar
.valid_range(cx
);
2447 let msg
= if !range
.contains(0) {
2449 } else if init
== InitKind
::Uninit
&& !scalar
.is_always_valid(cx
) {
2450 // Prefer reporting on the fields over the entire struct for uninit,
2451 // as the information bubbles out and it may be unclear why the type can't
2452 // be null from just its outside signature.
2454 "must be initialized inside its custom valid range"
2458 if let Some(field_err
) = &mut field_err
{
2459 // Most of the time, if the field error is the same as the struct error,
2460 // the struct error only happens because of the field error.
2461 if field_err
.message
.contains(msg
) {
2462 field_err
.message
= format
!("because {}", field_err
.message
);
2465 return Some(InitError
::from(format
!("`{ty}` {msg}")).nested(field_err
));
2471 /// Return `Some` only if we are sure this type does *not*
2472 /// allow zero initialization.
2473 fn ty_find_init_error
<'tcx
>(
2474 cx
: &LateContext
<'tcx
>,
2477 ) -> Option
<InitError
> {
2478 use rustc_type_ir
::TyKind
::*;
2480 // Primitive types that don't like 0 as a value.
2481 Ref(..) => Some("references must be non-null".into()),
2482 Adt(..) if ty
.is_box() => Some("`Box` must be non-null".into()),
2483 FnPtr(..) => Some("function pointers must be non-null".into()),
2484 Never
=> Some("the `!` type has no valid value".into()),
2485 RawPtr(tm
) if matches
!(tm
.ty
.kind(), Dynamic(..)) =>
2486 // raw ptr to dyn Trait
2488 Some("the vtable of a wide raw pointer must be non-null".into())
2490 // Primitive types with other constraints.
2491 Bool
if init
== InitKind
::Uninit
=> {
2492 Some("booleans must be either `true` or `false`".into())
2494 Char
if init
== InitKind
::Uninit
=> {
2495 Some("characters must be a valid Unicode codepoint".into())
2497 Int(_
) | Uint(_
) if init
== InitKind
::Uninit
=> {
2498 Some("integers must be initialized".into())
2500 Float(_
) if init
== InitKind
::Uninit
=> Some("floats must be initialized".into()),
2501 RawPtr(_
) if init
== InitKind
::Uninit
=> {
2502 Some("raw pointers must be initialized".into())
2504 // Recurse and checks for some compound types. (but not unions)
2505 Adt(adt_def
, args
) if !adt_def
.is_union() => {
2507 if adt_def
.is_struct() {
2508 return variant_find_init_error(
2511 adt_def
.non_enum_variant(),
2518 let span
= cx
.tcx
.def_span(adt_def
.did());
2519 let mut potential_variants
= adt_def
.variants().iter().filter_map(|variant
| {
2520 let definitely_inhabited
= match variant
2521 .inhabited_predicate(cx
.tcx
, *adt_def
)
2522 .instantiate(cx
.tcx
, args
)
2523 .apply_any_module(cx
.tcx
, cx
.param_env
)
2525 // Entirely skip uninhabited variants.
2526 Some(false) => return None
,
2527 // Forward the others, but remember which ones are definitely inhabited.
2531 Some((variant
, definitely_inhabited
))
2533 let Some(first_variant
) = potential_variants
.next() else {
2535 InitError
::from("enums with no inhabited variants have no valid value")
2539 // So we have at least one potentially inhabited variant. Might we have two?
2540 let Some(second_variant
) = potential_variants
.next() else {
2541 // There is only one potentially inhabited variant. So we can recursively check that variant!
2542 return variant_find_init_error(
2547 "field of the only potentially inhabited enum variant",
2551 // So we have at least two potentially inhabited variants.
2552 // If we can prove that we have at least two *definitely* inhabited variants,
2553 // then we have a tag and hence leaving this uninit is definitely disallowed.
2554 // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
2555 if init
== InitKind
::Uninit
{
2556 let definitely_inhabited
= (first_variant
.1 as usize)
2557 + (second_variant
.1 as usize)
2558 + potential_variants
2559 .filter(|(_variant
, definitely_inhabited
)| *definitely_inhabited
)
2561 if definitely_inhabited
> 1 {
2562 return Some(InitError
::from(
2563 "enums with multiple inhabited variants have to be initialized to a variant",
2567 // We couldn't find anything wrong here.
2571 // Proceed recursively, check all fields.
2572 ty
.tuple_fields().iter().find_map(|field
| ty_find_init_error(cx
, field
, init
))
2575 if matches
!(len
.try_eval_target_usize(cx
.tcx
, cx
.param_env
), Some(v
) if v
> 0) {
2576 // Array length known at array non-empty -- recurse.
2577 ty_find_init_error(cx
, *ty
, init
)
2579 // Empty array or size unknown.
2583 // Conservative fallback.
2588 if let Some(init
) = is_dangerous_init(cx
, expr
) {
2589 // This conjures an instance of a type out of nothing,
2590 // using zeroed or uninitialized memory.
2591 // We are extremely conservative with what we warn about.
2592 let conjured_ty
= cx
.typeck_results().expr_ty(expr
);
2593 if let Some(err
) = with_no_trimmed_paths
!(ty_find_init_error(cx
, conjured_ty
, init
)) {
2594 let msg
= match init
{
2595 InitKind
::Zeroed
=> fluent
::lint_builtin_unpermitted_type_init_zeroed
,
2596 InitKind
::Uninit
=> fluent
::lint_builtin_unpermitted_type_init_uninit
,
2598 let sub
= BuiltinUnpermittedTypeInitSub { err }
;
2599 cx
.emit_spanned_lint(
2602 BuiltinUnpermittedTypeInit
{
2616 /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2617 /// which causes [undefined behavior].
2622 /// # #![allow(unused)]
2625 /// let x = &*ptr::null::<i32>();
2626 /// let x = ptr::addr_of!(*ptr::null::<i32>());
2627 /// let x = *(0 as *const i32);
2635 /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
2636 /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
2638 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2641 "detects when an null pointer is dereferenced"
2644 declare_lint_pass
!(DerefNullPtr
=> [DEREF_NULLPTR
]);
2646 impl<'tcx
> LateLintPass
<'tcx
> for DerefNullPtr
{
2647 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &hir
::Expr
<'_
>) {
2648 /// test if expression is a null ptr
2649 fn is_null_ptr(cx
: &LateContext
<'_
>, expr
: &hir
::Expr
<'_
>) -> bool
{
2651 rustc_hir
::ExprKind
::Cast(ref expr
, ref ty
) => {
2652 if let rustc_hir
::TyKind
::Ptr(_
) = ty
.kind
{
2653 return is_zero(expr
) || is_null_ptr(cx
, expr
);
2656 // check for call to `core::ptr::null` or `core::ptr::null_mut`
2657 rustc_hir
::ExprKind
::Call(ref path
, _
) => {
2658 if let rustc_hir
::ExprKind
::Path(ref qpath
) = path
.kind
{
2659 if let Some(def_id
) = cx
.qpath_res(qpath
, path
.hir_id
).opt_def_id() {
2661 cx
.tcx
.get_diagnostic_name(def_id
),
2662 Some(sym
::ptr_null
| sym
::ptr_null_mut
)
2672 /// test if expression is the literal `0`
2673 fn is_zero(expr
: &hir
::Expr
<'_
>) -> bool
{
2675 rustc_hir
::ExprKind
::Lit(ref lit
) => {
2676 if let LitKind
::Int(a
, _
) = lit
.node
{
2685 if let rustc_hir
::ExprKind
::Unary(rustc_hir
::UnOp
::Deref
, expr_deref
) = expr
.kind
{
2686 if is_null_ptr(cx
, expr_deref
) {
2687 cx
.emit_spanned_lint(
2690 BuiltinDerefNullptr { label: expr.span }
,
2698 /// The `named_asm_labels` lint detects the use of named labels in the
2699 /// inline `asm!` macro.
2703 /// ```rust,compile_fail
2704 /// # #![feature(asm_experimental_arch)]
2705 /// use std::arch::asm;
2709 /// asm!("foo: bar");
2718 /// LLVM is allowed to duplicate inline assembly blocks for any
2719 /// reason, for example when it is in a function that gets inlined. Because
2720 /// of this, GNU assembler [local labels] *must* be used instead of labels
2721 /// with a name. Using named labels might cause assembler or linker errors.
2723 /// See the explanation in [Rust By Example] for more details.
2725 /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
2726 /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2727 pub NAMED_ASM_LABELS
,
2729 "named labels in inline assembly",
2732 declare_lint_pass
!(NamedAsmLabels
=> [NAMED_ASM_LABELS
]);
2734 impl<'tcx
> LateLintPass
<'tcx
> for NamedAsmLabels
{
2735 #[allow(rustc::diagnostic_outside_of_impl)]
2736 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx hir
::Expr
<'tcx
>) {
2738 kind
: hir
::ExprKind
::InlineAsm(hir
::InlineAsm { template_strs, .. }
),
2742 for (template_sym
, template_snippet
, template_span
) in template_strs
.iter() {
2743 let template_str
= template_sym
.as_str();
2744 let find_label_span
= |needle
: &str| -> Option
<Span
> {
2745 if let Some(template_snippet
) = template_snippet
{
2746 let snippet
= template_snippet
.as_str();
2747 if let Some(pos
) = snippet
.find(needle
) {
2751 .unwrap_or(snippet
[pos
..].len() - 1);
2752 let inner
= InnerSpan
::new(pos
, end
);
2753 return Some(template_span
.from_inner(inner
));
2760 let mut found_labels
= Vec
::new();
2762 // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
2763 let statements
= template_str
.split(|c
| matches
!(c
, '
\n'
| '
;'
));
2764 for statement
in statements
{
2765 // If there's a comment, trim it from the statement
2766 let statement
= statement
.find("//").map_or(statement
, |idx
| &statement
[..idx
]);
2767 let mut start_idx
= 0;
2768 for (idx
, _
) in statement
.match_indices('
:'
) {
2769 let possible_label
= statement
[start_idx
..idx
].trim();
2770 let mut chars
= possible_label
.chars();
2771 let Some(c
) = chars
.next() else {
2772 // Empty string means a leading ':' in this section, which is not a label
2775 // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
2776 if (c
.is_alphabetic() || matches
!(c
, '
.'
| '_'
))
2777 && chars
.all(|c
| c
.is_alphanumeric() || matches
!(c
, '_'
| '$'
))
2779 found_labels
.push(possible_label
);
2781 // If we encounter a non-label, there cannot be any further labels, so stop checking
2785 start_idx
= idx
+ 1;
2789 debug
!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels
);
2791 if found_labels
.len() > 0 {
2792 let spans
= found_labels
2794 .filter_map(|label
| find_label_span(label
))
2795 .collect
::<Vec
<Span
>>();
2796 // If there were labels but we couldn't find a span, combine the warnings and use the template span
2797 let target_spans
: MultiSpan
=
2798 if spans
.len() > 0 { spans.into() }
else { (*template_span).into() }
;
2800 cx
.lookup_with_diagnostics(
2803 fluent
::lint_builtin_asm_labels
,
2805 BuiltinLintDiagnostics
::NamedAsmLabel(
2806 "only local labels of the form `<number>:` should be used in inline asm"
2817 /// The `special_module_name` lint detects module
2818 /// declarations for files that have a special meaning.
2822 /// ```rust,compile_fail
2834 /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
2835 /// library or binary crate, so declaring them as modules
2836 /// will lead to miscompilation of the crate unless configured
2839 /// To access a library from a binary target within the same crate,
2840 /// use `your_crate_name::` as the path instead of `lib::`:
2842 /// ```rust,compile_fail
2843 /// // bar/src/lib.rs
2848 /// // bar/src/main.rs
2854 /// Binary targets cannot be used as libraries and so declaring
2855 /// one as a module is not allowed.
2856 pub SPECIAL_MODULE_NAME
,
2858 "module declarations for files with a special meaning",
2861 declare_lint_pass
!(SpecialModuleName
=> [SPECIAL_MODULE_NAME
]);
2863 impl EarlyLintPass
for SpecialModuleName
{
2864 fn check_crate(&mut self, cx
: &EarlyContext
<'_
>, krate
: &ast
::Crate
) {
2865 for item
in &krate
.items
{
2866 if let ast
::ItemKind
::Mod(
2868 ast
::ModKind
::Unloaded
| ast
::ModKind
::Loaded(_
, ast
::Inline
::No
, _
),
2871 if item
.attrs
.iter().any(|a
| a
.has_name(sym
::path
)) {
2875 match item
.ident
.name
.as_str() {
2876 "lib" => cx
.emit_spanned_lint(
2877 SPECIAL_MODULE_NAME
,
2879 BuiltinSpecialModuleNameUsed
::Lib
,
2881 "main" => cx
.emit_spanned_lint(
2882 SPECIAL_MODULE_NAME
,
2884 BuiltinSpecialModuleNameUsed
::Main
,
2893 pub use rustc_session
::lint
::builtin
::UNEXPECTED_CFGS
;
2895 declare_lint_pass
!(UnexpectedCfgs
=> [UNEXPECTED_CFGS
]);
2897 impl EarlyLintPass
for UnexpectedCfgs
{
2898 fn check_crate(&mut self, cx
: &EarlyContext
<'_
>, _
: &ast
::Crate
) {
2899 let cfg
= &cx
.sess().parse_sess
.config
;
2900 let check_cfg
= &cx
.sess().parse_sess
.check_config
;
2901 for &(name
, value
) in cfg
{
2902 match check_cfg
.expecteds
.get(&name
) {
2903 Some(ExpectedValues
::Some(values
)) if !values
.contains(&value
) => {
2904 let value
= value
.unwrap_or(kw
::Empty
);
2905 cx
.emit_lint(UNEXPECTED_CFGS
, BuiltinUnexpectedCliConfigValue { name, value }
);
2907 None
if check_cfg
.exhaustive_names
=> {
2908 cx
.emit_lint(UNEXPECTED_CFGS
, BuiltinUnexpectedCliConfigName { name }
);
2910 _
=> { /* expected */ }