1 //! Lints, aka compiler warnings.
3 //! A 'lint' check is a kind of miscellaneous constraint that a user _might_
4 //! want to enforce, but might reasonably want to permit as well, on a
5 //! module-by-module basis. They contrast with static constraints enforced by
6 //! other phases of the compiler, which are generally required to hold in order
7 //! to compile the program at all.
9 //! Most lints can be written as `LintPass` instances. These run after
10 //! all other analyses. The `LintPass`es built into rustc are defined
11 //! within `builtin.rs`, which has further comments on how to add such a lint.
12 //! rustc can also load user-defined lint plugins via the plugin mechanism.
14 //! Some of rustc's lints are defined elsewhere in the compiler and work by
15 //! calling `add_lint()` on the overall `Session` object. This works when
16 //! it happens before the main lint pass, which emits the lints stored by
17 //! `add_lint()`. To emit lints after the main lint pass (from codegen, for
18 //! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
21 pub use self::Level
::*;
22 pub use self::LintSource
::*;
24 use rustc_data_structures
::sync
;
26 use crate::hir
::def_id
::{CrateNum, LOCAL_CRATE}
;
27 use crate::hir
::intravisit
;
29 use crate::lint
::builtin
::BuiltinLintDiagnostics
;
30 use crate::lint
::builtin
::parser
::ILL_FORMED_ATTRIBUTE_INPUT
;
31 use crate::session
::{Session, DiagnosticMessageId}
;
32 use crate::ty
::TyCtxt
;
33 use crate::ty
::query
::Providers
;
34 use crate::util
::nodemap
::NodeMap
;
35 use errors
::{DiagnosticBuilder, DiagnosticId}
;
38 use syntax
::source_map
::{MultiSpan, ExpnFormat, CompilerDesugaringKind}
;
39 use syntax
::early_buffered_lints
::BufferedEarlyLintId
;
40 use syntax
::edition
::Edition
;
41 use syntax
::symbol
::{Symbol, sym}
;
44 pub use crate::lint
::context
::{LateContext
, EarlyContext
, LintContext
, LintStore
,
45 check_crate
, check_ast_crate
, late_lint_mod
, CheckLintNameResult
,
46 FutureIncompatibleInfo
, BufferedEarlyLint
,};
48 /// Specification of a single lint.
49 #[derive(Copy, Clone, Debug)]
51 /// A string identifier for the lint.
53 /// This identifies the lint in attributes and in command-line arguments.
54 /// In those contexts it is always lowercase, but this field is compared
55 /// in a way which is case-insensitive for ASCII characters. This allows
56 /// `declare_lint!()` invocations to follow the convention of upper-case
57 /// statics without repeating the name.
59 /// The name is written with underscores, e.g., "unused_imports".
60 /// On the command line, underscores become dashes.
61 pub name
: &'
static str,
63 /// Default level for the lint.
64 pub default_level
: Level
,
66 /// Description of the lint or the issue it detects.
68 /// e.g., "imports that are never used"
69 pub desc
: &'
static str,
71 /// Starting at the given edition, default to the given lint level. If this is `None`, then use
73 pub edition_lint_opts
: Option
<(Edition
, Level
)>,
75 /// `true` if this lint is reported even inside expansions of external macros.
76 pub report_in_external_macro
: bool
,
80 /// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`.
81 pub fn from_parser_lint_id(lint_id
: BufferedEarlyLintId
) -> &'
static Self {
83 BufferedEarlyLintId
::IllFormedAttributeInput
=> ILL_FORMED_ATTRIBUTE_INPUT
,
87 /// Gets the lint's name, with ASCII letters converted to lowercase.
88 pub fn name_lower(&self) -> String
{
89 self.name
.to_ascii_lowercase()
92 pub fn default_level(&self, session
: &Session
) -> Level
{
93 self.edition_lint_opts
94 .filter(|(e
, _
)| *e
<= session
.edition())
96 .unwrap_or(self.default_level
)
100 /// Declares a static item of type `&'static Lint`.
102 macro_rules
! declare_lint
{
103 ($vis
: vis $NAME
: ident
, $Level
: ident
, $desc
: expr
) => (
104 declare_lint
!{$vis $NAME, $Level, $desc, false}
106 ($vis
: vis $NAME
: ident
, $Level
: ident
, $desc
: expr
, report_in_external_macro
: $rep
: expr
) => (
107 declare_lint
!{$vis $NAME, $Level, $desc, $rep}
109 ($vis
: vis $NAME
: ident
, $Level
: ident
, $desc
: expr
, $external
: expr
) => (
110 $vis
static $NAME
: &$
crate::lint
::Lint
= &$
crate::lint
::Lint
{
111 name
: stringify
!($NAME
),
112 default_level
: $
crate::lint
::$Level
,
114 edition_lint_opts
: None
,
115 report_in_external_macro
: $external
,
118 ($vis
: vis $NAME
: ident
, $Level
: ident
, $desc
: expr
,
119 $lint_edition
: expr
=> $edition_level
: ident
121 $vis
static $NAME
: &$
crate::lint
::Lint
= &$
crate::lint
::Lint
{
122 name
: stringify
!($NAME
),
123 default_level
: $
crate::lint
::$Level
,
125 edition_lint_opts
: Some(($lint_edition
, $
crate::lint
::Level
::$edition_level
)),
126 report_in_external_macro
: false,
132 macro_rules
! declare_tool_lint
{
134 $
(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
136 declare_tool_lint
!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
139 $
(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
140 report_in_external_macro
: $rep
:expr
142 declare_tool_lint
!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
145 $
(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
149 $vis
static $NAME
: &$
crate::lint
::Lint
= &$
crate::lint
::Lint
{
150 name
: &concat
!(stringify
!($tool
), "::", stringify
!($NAME
)),
151 default_level
: $
crate::lint
::$Level
,
153 edition_lint_opts
: None
,
154 report_in_external_macro
: $external
,
159 /// Declares a static `LintArray` and return it as an expression.
161 macro_rules
! lint_array
{
162 ($
( $lint
:expr
),* ,) => { lint_array!( $($lint),* ) }
;
163 ($
( $lint
:expr
),*) => {{
168 pub type LintArray
= Vec
<&'
static Lint
>;
171 fn name(&self) -> &'
static str;
173 /// Gets descriptions of the lints this `LintPass` object can emit.
175 /// N.B., there is no enforcement that the object only emits lints it registered.
176 /// And some `rustc` internal `LintPass`es register lints to be emitted by other
177 /// parts of the compiler. If you want enforced access restrictions for your
178 /// `Lint`, make it a private `static` item in its own module.
179 fn get_lints(&self) -> LintArray
;
182 /// Implements `LintPass for $name` with the given list of `Lint` statics.
184 macro_rules
! impl_lint_pass
{
185 ($name
:ident
=> [$
($lint
:expr
),* $
(,)?
]) => {
186 impl LintPass
for $name
{
187 fn name(&self) -> &'
static str { stringify!($name) }
188 fn get_lints(&self) -> LintArray { $crate::lint_array!($($lint),*) }
193 /// Declares a type named `$name` which implements `LintPass`.
194 /// To the right of `=>` a comma separated list of `Lint` statics is given.
196 macro_rules
! declare_lint_pass
{
197 ($
(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
198 $
(#[$m])* #[derive(Copy, Clone)] pub struct $name;
199 $
crate::impl_lint_pass
!($name
=> [$
($lint
),*]);
204 macro_rules
! late_lint_methods
{
205 ($
macro:path
, $args
:tt
, [$hir
:tt
]) => (
206 $
macro!($args
, [$hir
], [
207 fn check_body(a
: &$hir hir
::Body
);
208 fn check_body_post(a
: &$hir hir
::Body
);
209 fn check_name(a
: Span
, b
: ast
::Name
);
210 fn check_crate(a
: &$hir hir
::Crate
);
211 fn check_crate_post(a
: &$hir hir
::Crate
);
212 fn check_mod(a
: &$hir hir
::Mod
, b
: Span
, c
: hir
::HirId
);
213 fn check_mod_post(a
: &$hir hir
::Mod
, b
: Span
, c
: hir
::HirId
);
214 fn check_foreign_item(a
: &$hir hir
::ForeignItem
);
215 fn check_foreign_item_post(a
: &$hir hir
::ForeignItem
);
216 fn check_item(a
: &$hir hir
::Item
);
217 fn check_item_post(a
: &$hir hir
::Item
);
218 fn check_local(a
: &$hir hir
::Local
);
219 fn check_block(a
: &$hir hir
::Block
);
220 fn check_block_post(a
: &$hir hir
::Block
);
221 fn check_stmt(a
: &$hir hir
::Stmt
);
222 fn check_arm(a
: &$hir hir
::Arm
);
223 fn check_pat(a
: &$hir hir
::Pat
);
224 fn check_expr(a
: &$hir hir
::Expr
);
225 fn check_expr_post(a
: &$hir hir
::Expr
);
226 fn check_ty(a
: &$hir hir
::Ty
);
227 fn check_generic_param(a
: &$hir hir
::GenericParam
);
228 fn check_generics(a
: &$hir hir
::Generics
);
229 fn check_where_predicate(a
: &$hir hir
::WherePredicate
);
230 fn check_poly_trait_ref(a
: &$hir hir
::PolyTraitRef
, b
: hir
::TraitBoundModifier
);
232 a
: hir
::intravisit
::FnKind
<$hir
>,
233 b
: &$hir hir
::FnDecl
,
238 a
: hir
::intravisit
::FnKind
<$hir
>,
239 b
: &$hir hir
::FnDecl
,
244 fn check_trait_item(a
: &$hir hir
::TraitItem
);
245 fn check_trait_item_post(a
: &$hir hir
::TraitItem
);
246 fn check_impl_item(a
: &$hir hir
::ImplItem
);
247 fn check_impl_item_post(a
: &$hir hir
::ImplItem
);
249 a
: &$hir hir
::VariantData
,
251 c
: &$hir hir
::Generics
,
254 fn check_struct_def_post(
255 a
: &$hir hir
::VariantData
,
257 c
: &$hir hir
::Generics
,
260 fn check_struct_field(a
: &$hir hir
::StructField
);
261 fn check_variant(a
: &$hir hir
::Variant
, b
: &$hir hir
::Generics
);
262 fn check_variant_post(a
: &$hir hir
::Variant
, b
: &$hir hir
::Generics
);
263 fn check_lifetime(a
: &$hir hir
::Lifetime
);
264 fn check_path(a
: &$hir hir
::Path
, b
: hir
::HirId
);
265 fn check_attribute(a
: &$hir ast
::Attribute
);
267 /// Called when entering a syntax node that can have lint attributes such
268 /// as `#[allow(...)]`. Called with *all* the attributes of that node.
269 fn enter_lint_attrs(a
: &$hir
[ast
::Attribute
]);
271 /// Counterpart to `enter_lint_attrs`.
272 fn exit_lint_attrs(a
: &$hir
[ast
::Attribute
]);
277 /// Trait for types providing lint checks.
279 /// Each `check` method checks a single syntax node, and should not
280 /// invoke methods recursively (unlike `Visitor`). By default they
283 // FIXME: eliminate the duplication with `Visitor`. But this also
284 // contains a few lint-specific methods with no equivalent in `Visitor`.
286 macro_rules
! expand_lint_pass_methods
{
287 ($context
:ty
, [$
($
(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
288 $
(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
292 macro_rules
! declare_late_lint_pass
{
293 ([], [$hir
:tt
], [$
($methods
:tt
)*]) => (
294 pub trait LateLintPass
<'a
, $hir
>: LintPass
{
295 fn fresh_late_pass(&self) -> LateLintPassObject
{
298 expand_lint_pass_methods
!(&LateContext
<'a
, $hir
>, [$
($methods
)*]);
303 late_lint_methods
!(declare_late_lint_pass
, [], ['tcx
]);
306 macro_rules
! expand_combined_late_lint_pass_method
{
307 ([$
($passes
:ident
),*], $
self: ident
, $name
: ident
, $params
:tt
) => ({
308 $
($
self.$passes
.$name $params
;)*
313 macro_rules
! expand_combined_late_lint_pass_methods
{
314 ($passes
:tt
, [$
($
(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
315 $
(fn $
name(&mut self, context
: &LateContext
<'a
, 'tcx
>, $
($param
: $arg
),*) {
316 expand_combined_late_lint_pass_method
!($passes
, self, $name
, (context
, $
($param
),*));
322 macro_rules
! declare_combined_late_lint_pass
{
323 ([$v
:vis $name
:ident
, [$
($passes
:ident
: $constructor
:expr
,)*]], [$hir
:tt
], $methods
:tt
) => (
324 #[allow(non_snake_case)]
326 $
($passes
: $passes
,)*
330 $v
fn new() -> Self {
332 $
($passes
: $constructor
,)*
337 impl<'a
, 'tcx
> LateLintPass
<'a
, 'tcx
> for $name
{
338 expand_combined_late_lint_pass_methods
!([$
($passes
),*], $methods
);
341 impl LintPass
for $name
{
342 fn name(&self) -> &'
static str {
346 fn get_lints(&self) -> LintArray
{
347 let mut lints
= Vec
::new();
348 $
(lints
.extend_from_slice(&self.$passes
.get_lints());)*
356 macro_rules
! early_lint_methods
{
357 ($
macro:path
, $args
:tt
) => (
359 fn check_ident(a
: ast
::Ident
);
360 fn check_crate(a
: &ast
::Crate
);
361 fn check_crate_post(a
: &ast
::Crate
);
362 fn check_mod(a
: &ast
::Mod
, b
: Span
, c
: ast
::NodeId
);
363 fn check_mod_post(a
: &ast
::Mod
, b
: Span
, c
: ast
::NodeId
);
364 fn check_foreign_item(a
: &ast
::ForeignItem
);
365 fn check_foreign_item_post(a
: &ast
::ForeignItem
);
366 fn check_item(a
: &ast
::Item
);
367 fn check_item_post(a
: &ast
::Item
);
368 fn check_local(a
: &ast
::Local
);
369 fn check_block(a
: &ast
::Block
);
370 fn check_block_post(a
: &ast
::Block
);
371 fn check_stmt(a
: &ast
::Stmt
);
372 fn check_arm(a
: &ast
::Arm
);
373 fn check_pat(a
: &ast
::Pat
);
374 fn check_pat_post(a
: &ast
::Pat
);
375 fn check_expr(a
: &ast
::Expr
);
376 fn check_expr_post(a
: &ast
::Expr
);
377 fn check_ty(a
: &ast
::Ty
);
378 fn check_generic_param(a
: &ast
::GenericParam
);
379 fn check_generics(a
: &ast
::Generics
);
380 fn check_where_predicate(a
: &ast
::WherePredicate
);
381 fn check_poly_trait_ref(a
: &ast
::PolyTraitRef
,
382 b
: &ast
::TraitBoundModifier
);
383 fn check_fn(a
: syntax
::visit
::FnKind
<'_
>, b
: &ast
::FnDecl
, c
: Span
, d_
: ast
::NodeId
);
385 a
: syntax
::visit
::FnKind
<'_
>,
390 fn check_trait_item(a
: &ast
::TraitItem
);
391 fn check_trait_item_post(a
: &ast
::TraitItem
);
392 fn check_impl_item(a
: &ast
::ImplItem
);
393 fn check_impl_item_post(a
: &ast
::ImplItem
);
395 a
: &ast
::VariantData
,
400 fn check_struct_def_post(
401 a
: &ast
::VariantData
,
406 fn check_struct_field(a
: &ast
::StructField
);
407 fn check_variant(a
: &ast
::Variant
, b
: &ast
::Generics
);
408 fn check_variant_post(a
: &ast
::Variant
, b
: &ast
::Generics
);
409 fn check_lifetime(a
: &ast
::Lifetime
);
410 fn check_path(a
: &ast
::Path
, b
: ast
::NodeId
);
411 fn check_attribute(a
: &ast
::Attribute
);
412 fn check_mac_def(a
: &ast
::MacroDef
, b
: ast
::NodeId
);
413 fn check_mac(a
: &ast
::Mac
);
415 /// Called when entering a syntax node that can have lint attributes such
416 /// as `#[allow(...)]`. Called with *all* the attributes of that node.
417 fn enter_lint_attrs(a
: &[ast
::Attribute
]);
419 /// Counterpart to `enter_lint_attrs`.
420 fn exit_lint_attrs(a
: &[ast
::Attribute
]);
425 macro_rules
! expand_early_lint_pass_methods
{
426 ($context
:ty
, [$
($
(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
427 $
(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
431 macro_rules
! declare_early_lint_pass
{
432 ([], [$
($methods
:tt
)*]) => (
433 pub trait EarlyLintPass
: LintPass
{
434 expand_early_lint_pass_methods
!(&EarlyContext
<'_
>, [$
($methods
)*]);
439 early_lint_methods
!(declare_early_lint_pass
, []);
442 macro_rules
! expand_combined_early_lint_pass_method
{
443 ([$
($passes
:ident
),*], $
self: ident
, $name
: ident
, $params
:tt
) => ({
444 $
($
self.$passes
.$name $params
;)*
449 macro_rules
! expand_combined_early_lint_pass_methods
{
450 ($passes
:tt
, [$
($
(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
451 $
(fn $
name(&mut self, context
: &EarlyContext
<'_
>, $
($param
: $arg
),*) {
452 expand_combined_early_lint_pass_method
!($passes
, self, $name
, (context
, $
($param
),*));
458 macro_rules
! declare_combined_early_lint_pass
{
459 ([$v
:vis $name
:ident
, [$
($passes
:ident
: $constructor
:expr
,)*]], $methods
:tt
) => (
460 #[allow(non_snake_case)]
462 $
($passes
: $passes
,)*
466 $v
fn new() -> Self {
468 $
($passes
: $constructor
,)*
473 impl EarlyLintPass
for $name
{
474 expand_combined_early_lint_pass_methods
!([$
($passes
),*], $methods
);
477 impl LintPass
for $name
{
478 fn name(&self) -> &'
static str {
482 fn get_lints(&self) -> LintArray
{
483 let mut lints
= Vec
::new();
484 $
(lints
.extend_from_slice(&self.$passes
.get_lints());)*
491 /// A lint pass boxed up as a trait object.
492 pub type EarlyLintPassObject
= Box
<dyn EarlyLintPass
+ sync
::Send
+ sync
::Sync
+ '
static>;
493 pub type LateLintPassObject
= Box
<dyn for<'a
, 'tcx
> LateLintPass
<'a
, 'tcx
> + sync
::Send
494 + sync
::Sync
+ '
static>;
498 /// Identifies a lint known to the compiler.
499 #[derive(Clone, Copy, Debug)]
501 // Identity is based on pointer equality of this field.
505 impl PartialEq
for LintId
{
506 fn eq(&self, other
: &LintId
) -> bool
{
507 ptr
::eq(self.lint
, other
.lint
)
511 impl Eq
for LintId { }
513 impl hash
::Hash
for LintId
{
514 fn hash
<H
: hash
::Hasher
>(&self, state
: &mut H
) {
515 let ptr
= self.lint
as *const Lint
;
521 /// Gets the `LintId` for a `Lint`.
522 pub fn of(lint
: &'
static Lint
) -> LintId
{
528 pub fn lint_name_raw(&self) -> &'
static str {
532 /// Gets the name of the lint.
533 pub fn to_string(&self) -> String
{
534 self.lint
.name_lower()
538 /// Setting for how to handle a lint.
539 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
541 Allow
, Warn
, Deny
, Forbid
,
544 impl_stable_hash_for
!(enum self::Level
{
552 /// Converts a level to a lower-case string.
553 pub fn as_str(self) -> &'
static str {
562 /// Converts a lower-case string to a level.
563 pub fn from_str(x
: &str) -> Option
<Level
> {
565 "allow" => Some(Allow
),
566 "warn" => Some(Warn
),
567 "deny" => Some(Deny
),
568 "forbid" => Some(Forbid
),
573 /// Converts a symbol to a level.
574 pub fn from_symbol(x
: Symbol
) -> Option
<Level
> {
576 sym
::allow
=> Some(Allow
),
577 sym
::warn
=> Some(Warn
),
578 sym
::deny
=> Some(Deny
),
579 sym
::forbid
=> Some(Forbid
),
585 /// How a lint level was set.
586 #[derive(Clone, Copy, PartialEq, Eq)]
587 pub enum LintSource
{
588 /// Lint is at the default level as declared
589 /// in rustc or a plugin.
592 /// Lint level was set by an attribute.
593 Node(ast
::Name
, Span
, Option
<Symbol
> /* RFC 2383 reason */),
595 /// Lint level was set by a command-line flag.
599 impl_stable_hash_for
!(enum self::LintSource
{
601 Node(name
, span
, reason
),
605 pub type LevelSource
= (Level
, LintSource
);
612 pub use self::levels
::{LintLevelSets, LintLevelMap}
;
615 pub struct LintBuffer
{
616 map
: NodeMap
<Vec
<BufferedEarlyLint
>>,
620 pub fn add_lint(&mut self,
625 diagnostic
: BuiltinLintDiagnostics
) {
626 let early_lint
= BufferedEarlyLint
{
627 lint_id
: LintId
::of(lint
),
630 msg
: msg
.to_string(),
633 let arr
= self.map
.entry(id
).or_default();
634 if !arr
.contains(&early_lint
) {
635 arr
.push(early_lint
);
639 pub fn take(&mut self, id
: ast
::NodeId
) -> Vec
<BufferedEarlyLint
> {
640 self.map
.remove(&id
).unwrap_or_default()
643 pub fn get_any(&self) -> Option
<&[BufferedEarlyLint
]> {
644 let key
= self.map
.keys().next().map(|k
| *k
);
645 key
.map(|k
| &self.map
[&k
][..])
649 pub fn struct_lint_level
<'a
>(sess
: &'a Session
,
653 span
: Option
<MultiSpan
>,
655 -> DiagnosticBuilder
<'a
>
657 let mut err
= match (level
, span
) {
658 (Level
::Allow
, _
) => return sess
.diagnostic().struct_dummy(),
659 (Level
::Warn
, Some(span
)) => sess
.struct_span_warn(span
, msg
),
660 (Level
::Warn
, None
) => sess
.struct_warn(msg
),
661 (Level
::Deny
, Some(span
)) |
662 (Level
::Forbid
, Some(span
)) => sess
.struct_span_err(span
, msg
),
663 (Level
::Deny
, None
) |
664 (Level
::Forbid
, None
) => sess
.struct_err(msg
),
667 let name
= lint
.name_lower();
669 LintSource
::Default
=> {
672 DiagnosticMessageId
::from(lint
),
673 &format
!("#[{}({})] on by default", level
.as_str(), name
));
675 LintSource
::CommandLine(lint_flag_val
) => {
676 let flag
= match level
{
679 Level
::Forbid
=> "-F",
680 Level
::Allow
=> panic
!(),
682 let hyphen_case_lint_name
= name
.replace("_", "-");
683 if lint_flag_val
.as_str() == name
{
686 DiagnosticMessageId
::from(lint
),
687 &format
!("requested on the command line with `{} {}`",
688 flag
, hyphen_case_lint_name
));
690 let hyphen_case_flag_val
= lint_flag_val
.as_str().replace("_", "-");
693 DiagnosticMessageId
::from(lint
),
694 &format
!("`{} {}` implied by `{} {}`",
695 flag
, hyphen_case_lint_name
, flag
,
696 hyphen_case_flag_val
));
699 LintSource
::Node(lint_attr_name
, src
, reason
) => {
700 if let Some(rationale
) = reason
{
701 err
.note(&rationale
.as_str());
703 sess
.diag_span_note_once(&mut err
, DiagnosticMessageId
::from(lint
),
704 src
, "lint level defined here");
705 if lint_attr_name
.as_str() != name
{
706 let level_str
= level
.as_str();
707 sess
.diag_note_once(&mut err
, DiagnosticMessageId
::from(lint
),
708 &format
!("#[{}({})] implied by #[{}({})]",
709 level_str
, name
, level_str
, lint_attr_name
));
714 err
.code(DiagnosticId
::Lint(name
));
716 // Check for future incompatibility lints and issue a stronger warning.
717 let lints
= sess
.lint_store
.borrow();
718 let lint_id
= LintId
::of(lint
);
719 let future_incompatible
= lints
.future_incompatible(lint_id
);
720 if let Some(future_incompatible
) = future_incompatible
{
721 const STANDARD_MESSAGE
: &str =
722 "this was previously accepted by the compiler but is being phased out; \
723 it will become a hard error";
725 let explanation
= if lint_id
== LintId
::of(builtin
::UNSTABLE_NAME_COLLISIONS
) {
726 "once this method is added to the standard library, \
727 the ambiguity may cause an error or change in behavior!"
729 } else if lint_id
== LintId
::of(builtin
::MUTABLE_BORROW_RESERVATION_CONFLICT
) {
730 "this borrowing pattern was not meant to be accepted, \
731 and may become a hard error in the future"
733 } else if let Some(edition
) = future_incompatible
.edition
{
734 format
!("{} in the {} edition!", STANDARD_MESSAGE
, edition
)
736 format
!("{} in a future release!", STANDARD_MESSAGE
)
738 let citation
= format
!("for more information, see {}",
739 future_incompatible
.reference
);
740 err
.warn(&explanation
);
744 // If this code originates in a foreign macro, aka something that this crate
745 // did not itself author, then it's likely that there's nothing this crate
746 // can do about it. We probably want to skip the lint entirely.
747 if err
.span
.primary_spans().iter().any(|s
| in_external_macro(sess
, *s
)) {
748 // Any suggestions made here are likely to be incorrect, so anything we
749 // emit shouldn't be automatically fixed by rustfix.
750 err
.allow_suggestions(false);
752 // If this is a future incompatible lint it'll become a hard error, so
753 // we have to emit *something*. Also allow lints to whitelist themselves
754 // on a case-by-case basis for emission in a foreign macro.
755 if future_incompatible
.is_none() && !lint
.report_in_external_macro
{
763 pub fn maybe_lint_level_root(tcx
: TyCtxt
<'_
>, id
: hir
::HirId
) -> bool
{
764 let attrs
= tcx
.hir().attrs(id
);
765 attrs
.iter().any(|attr
| Level
::from_symbol(attr
.name_or_empty()).is_some())
768 fn lint_levels
<'tcx
>(tcx
: TyCtxt
<'tcx
>, cnum
: CrateNum
) -> &'tcx LintLevelMap
{
769 assert_eq
!(cnum
, LOCAL_CRATE
);
770 let mut builder
= LintLevelMapBuilder
{
771 levels
: LintLevelSets
::builder(tcx
.sess
),
774 let krate
= tcx
.hir().krate();
776 let push
= builder
.levels
.push(&krate
.attrs
);
777 builder
.levels
.register_id(hir
::CRATE_HIR_ID
);
778 for macro_def
in &krate
.exported_macros
{
779 builder
.levels
.register_id(macro_def
.hir_id
);
781 intravisit
::walk_crate(&mut builder
, krate
);
782 builder
.levels
.pop(push
);
784 tcx
.arena
.alloc(builder
.levels
.build_map())
787 struct LintLevelMapBuilder
<'tcx
> {
788 levels
: levels
::LintLevelsBuilder
<'tcx
>,
792 impl LintLevelMapBuilder
<'tcx
> {
793 fn with_lint_attrs
<F
>(&mut self,
795 attrs
: &[ast
::Attribute
],
797 where F
: FnOnce(&mut Self)
799 let push
= self.levels
.push(attrs
);
801 self.levels
.register_id(id
);
804 self.levels
.pop(push
);
808 impl intravisit
::Visitor
<'tcx
> for LintLevelMapBuilder
<'tcx
> {
809 fn nested_visit_map
<'this
>(&'this
mut self) -> intravisit
::NestedVisitorMap
<'this
, 'tcx
> {
810 intravisit
::NestedVisitorMap
::All(&self.tcx
.hir())
813 fn visit_item(&mut self, it
: &'tcx hir
::Item
) {
814 self.with_lint_attrs(it
.hir_id
, &it
.attrs
, |builder
| {
815 intravisit
::walk_item(builder
, it
);
819 fn visit_foreign_item(&mut self, it
: &'tcx hir
::ForeignItem
) {
820 self.with_lint_attrs(it
.hir_id
, &it
.attrs
, |builder
| {
821 intravisit
::walk_foreign_item(builder
, it
);
825 fn visit_expr(&mut self, e
: &'tcx hir
::Expr
) {
826 self.with_lint_attrs(e
.hir_id
, &e
.attrs
, |builder
| {
827 intravisit
::walk_expr(builder
, e
);
831 fn visit_struct_field(&mut self, s
: &'tcx hir
::StructField
) {
832 self.with_lint_attrs(s
.hir_id
, &s
.attrs
, |builder
| {
833 intravisit
::walk_struct_field(builder
, s
);
837 fn visit_variant(&mut self,
838 v
: &'tcx hir
::Variant
,
839 g
: &'tcx hir
::Generics
,
840 item_id
: hir
::HirId
) {
841 self.with_lint_attrs(v
.node
.id
, &v
.node
.attrs
, |builder
| {
842 intravisit
::walk_variant(builder
, v
, g
, item_id
);
846 fn visit_local(&mut self, l
: &'tcx hir
::Local
) {
847 self.with_lint_attrs(l
.hir_id
, &l
.attrs
, |builder
| {
848 intravisit
::walk_local(builder
, l
);
852 fn visit_arm(&mut self, a
: &'tcx hir
::Arm
) {
853 self.with_lint_attrs(a
.hir_id
, &a
.attrs
, |builder
| {
854 intravisit
::walk_arm(builder
, a
);
858 fn visit_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
) {
859 self.with_lint_attrs(trait_item
.hir_id
, &trait_item
.attrs
, |builder
| {
860 intravisit
::walk_trait_item(builder
, trait_item
);
864 fn visit_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
) {
865 self.with_lint_attrs(impl_item
.hir_id
, &impl_item
.attrs
, |builder
| {
866 intravisit
::walk_impl_item(builder
, impl_item
);
871 pub fn provide(providers
: &mut Providers
<'_
>) {
872 providers
.lint_levels
= lint_levels
;
875 /// Returns whether `span` originates in a foreign crate's external macro.
877 /// This is used to test whether a lint should not even begin to figure out whether it should
878 /// be reported on the current node.
879 pub fn in_external_macro(sess
: &Session
, span
: Span
) -> bool
{
880 let info
= match span
.ctxt().outer_expn_info() {
882 // no ExpnInfo means this span doesn't come from a macro
883 None
=> return false,
887 ExpnFormat
::MacroAttribute(..) => true, // definitely a plugin
888 ExpnFormat
::CompilerDesugaring(CompilerDesugaringKind
::ForLoop
) => false,
889 ExpnFormat
::CompilerDesugaring(_
) => true, // well, it's "external"
890 ExpnFormat
::MacroBang(..) => {
891 let def_site
= match info
.def_site
{
893 // no span for the def_site means it's an external macro
897 match sess
.source_map().span_to_snippet(def_site
) {
898 Ok(code
) => !code
.starts_with("macro_rules"),
899 // no snippet = external macro or compiler-builtin expansion
906 /// Returns whether `span` originates in a derive macro's expansion
907 pub fn in_derive_expansion(span
: Span
) -> bool
{
908 let info
= match span
.ctxt().outer_expn_info() {
910 // no ExpnInfo means this span doesn't come from a macro
911 None
=> return false,
915 ExpnFormat
::MacroAttribute(symbol
) => symbol
.as_str().starts_with("derive("),