]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lint/src/builtin.rs
Rollup merge of #102240 - notriddle:notriddle/main-line-numbers, r=GuillaumeGomez
[rust.git] / compiler / rustc_lint / src / builtin.rs
1 //! Lints in the Rust compiler.
2 //!
3 //! This contains lints which can feasibly be implemented as their own
4 //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
5 //! definitions of lints that are emitted directly inside the main compiler.
6 //!
7 //! To add a new lint to rustc, declare it here using `declare_lint!()`.
8 //! Then add code to emit the new lint in the appropriate circumstances.
9 //! 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).
14 //!
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()`.
19 //!
20 //! If you define a new `LateLintPass`, you will also need to add it to the
21 //! `late_lint_methods!` invocation in `lib.rs`.
22
23 use crate::{
24     errors::BuiltinEllpisisInclusiveRangePatterns,
25     types::{transparent_newtype_field, CItemKind},
26     EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
27 };
28 use rustc_ast::attr;
29 use rustc_ast::tokenstream::{TokenStream, TokenTree};
30 use rustc_ast::visit::{FnCtxt, FnKind};
31 use rustc_ast::{self as ast, *};
32 use rustc_ast_pretty::pprust::{self, expr_to_string};
33 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
34 use rustc_data_structures::stack::ensure_sufficient_stack;
35 use rustc_errors::{
36     fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
37     LintDiagnosticBuilder, MultiSpan,
38 };
39 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
40 use rustc_hir as hir;
41 use rustc_hir::def::{DefKind, Res};
42 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
43 use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
44 use rustc_index::vec::Idx;
45 use rustc_middle::lint::in_external_macro;
46 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
47 use rustc_middle::ty::print::with_no_trimmed_paths;
48 use rustc_middle::ty::subst::GenericArgKind;
49 use rustc_middle::ty::Instance;
50 use rustc_middle::ty::{self, Ty, TyCtxt};
51 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
52 use rustc_span::edition::Edition;
53 use rustc_span::source_map::Spanned;
54 use rustc_span::symbol::{kw, sym, Ident, Symbol};
55 use rustc_span::{BytePos, InnerSpan, Span};
56 use rustc_target::abi::VariantIdx;
57 use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
58
59 use crate::nonstandard_style::{method_context, MethodLateContext};
60
61 use std::fmt::Write;
62
63 // hardwired lints from librustc_middle
64 pub use rustc_session::lint::builtin::*;
65
66 declare_lint! {
67     /// The `while_true` lint detects `while true { }`.
68     ///
69     /// ### Example
70     ///
71     /// ```rust,no_run
72     /// while true {
73     ///
74     /// }
75     /// ```
76     ///
77     /// {{produces}}
78     ///
79     /// ### Explanation
80     ///
81     /// `while true` should be replaced with `loop`. A `loop` expression is
82     /// the preferred way to write an infinite loop because it more directly
83     /// expresses the intent of the loop.
84     WHILE_TRUE,
85     Warn,
86     "suggest using `loop { }` instead of `while true { }`"
87 }
88
89 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
90
91 /// Traverse through any amount of parenthesis and return the first non-parens expression.
92 fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
93     while let ast::ExprKind::Paren(sub) = &expr.kind {
94         expr = sub;
95     }
96     expr
97 }
98
99 impl EarlyLintPass for WhileTrue {
100     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
101         if let ast::ExprKind::While(cond, _, label) = &e.kind {
102             if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
103                 if let ast::LitKind::Bool(true) = lit.kind {
104                     if !lit.span.from_expansion() {
105                         let condition_span = e.span.with_hi(cond.span.hi());
106                         cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
107                             lint.build(fluent::lint::builtin_while_true)
108                                 .span_suggestion_short(
109                                     condition_span,
110                                     fluent::lint::suggestion,
111                                     format!(
112                                         "{}loop",
113                                         label.map_or_else(String::new, |label| format!(
114                                             "{}: ",
115                                             label.ident,
116                                         ))
117                                     ),
118                                     Applicability::MachineApplicable,
119                                 )
120                                 .emit();
121                         })
122                     }
123                 }
124             }
125         }
126     }
127 }
128
129 declare_lint! {
130     /// The `box_pointers` lints use of the Box type.
131     ///
132     /// ### Example
133     ///
134     /// ```rust,compile_fail
135     /// #![deny(box_pointers)]
136     /// struct Foo {
137     ///     x: Box<isize>,
138     /// }
139     /// ```
140     ///
141     /// {{produces}}
142     ///
143     /// ### Explanation
144     ///
145     /// This lint is mostly historical, and not particularly useful. `Box<T>`
146     /// used to be built into the language, and the only way to do heap
147     /// allocation. Today's Rust can call into other allocators, etc.
148     BOX_POINTERS,
149     Allow,
150     "use of owned (Box type) heap memory"
151 }
152
153 declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
154
155 impl BoxPointers {
156     fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
157         for leaf in ty.walk() {
158             if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
159                 if leaf_ty.is_box() {
160                     cx.struct_span_lint(BOX_POINTERS, span, |lint| {
161                         lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
162                     });
163                 }
164             }
165         }
166     }
167 }
168
169 impl<'tcx> LateLintPass<'tcx> for BoxPointers {
170     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
171         match it.kind {
172             hir::ItemKind::Fn(..)
173             | hir::ItemKind::TyAlias(..)
174             | hir::ItemKind::Enum(..)
175             | hir::ItemKind::Struct(..)
176             | hir::ItemKind::Union(..) => {
177                 self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
178             }
179             _ => (),
180         }
181
182         // If it's a struct, we also have to check the fields' types
183         match it.kind {
184             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
185                 for struct_field in struct_def.fields() {
186                     let def_id = cx.tcx.hir().local_def_id(struct_field.hir_id);
187                     self.check_heap_type(cx, struct_field.span, cx.tcx.type_of(def_id));
188                 }
189             }
190             _ => (),
191         }
192     }
193
194     fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
195         let ty = cx.typeck_results().node_type(e.hir_id);
196         self.check_heap_type(cx, e.span, ty);
197     }
198 }
199
200 declare_lint! {
201     /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
202     /// instead of `Struct { x }` in a pattern.
203     ///
204     /// ### Example
205     ///
206     /// ```rust
207     /// struct Point {
208     ///     x: i32,
209     ///     y: i32,
210     /// }
211     ///
212     ///
213     /// fn main() {
214     ///     let p = Point {
215     ///         x: 5,
216     ///         y: 5,
217     ///     };
218     ///
219     ///     match p {
220     ///         Point { x: x, y: y } => (),
221     ///     }
222     /// }
223     /// ```
224     ///
225     /// {{produces}}
226     ///
227     /// ### Explanation
228     ///
229     /// The preferred style is to avoid the repetition of specifying both the
230     /// field name and the binding name if both identifiers are the same.
231     NON_SHORTHAND_FIELD_PATTERNS,
232     Warn,
233     "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
234 }
235
236 declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
237
238 impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
239     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
240         if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
241             let variant = cx
242                 .typeck_results()
243                 .pat_ty(pat)
244                 .ty_adt_def()
245                 .expect("struct pattern type is not an ADT")
246                 .variant_of_res(cx.qpath_res(qpath, pat.hir_id));
247             for fieldpat in field_pats {
248                 if fieldpat.is_shorthand {
249                     continue;
250                 }
251                 if fieldpat.span.from_expansion() {
252                     // Don't lint if this is a macro expansion: macro authors
253                     // shouldn't have to worry about this kind of style issue
254                     // (Issue #49588)
255                     continue;
256                 }
257                 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
258                     if cx.tcx.find_field_index(ident, &variant)
259                         == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
260                     {
261                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
262                             let suggested_ident =
263                                 format!("{}{}", binding_annot.prefix_str(), ident);
264                             lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
265                                 .set_arg("ident", ident.clone())
266                                 .span_suggestion(
267                                     fieldpat.span,
268                                     fluent::lint::suggestion,
269                                     suggested_ident,
270                                     Applicability::MachineApplicable,
271                                 )
272                                 .emit();
273                         });
274                     }
275                 }
276             }
277         }
278     }
279 }
280
281 declare_lint! {
282     /// The `unsafe_code` lint catches usage of `unsafe` code.
283     ///
284     /// ### Example
285     ///
286     /// ```rust,compile_fail
287     /// #![deny(unsafe_code)]
288     /// fn main() {
289     ///     unsafe {
290     ///
291     ///     }
292     /// }
293     /// ```
294     ///
295     /// {{produces}}
296     ///
297     /// ### Explanation
298     ///
299     /// This lint is intended to restrict the usage of `unsafe`, which can be
300     /// difficult to use correctly.
301     UNSAFE_CODE,
302     Allow,
303     "usage of `unsafe` code"
304 }
305
306 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
307
308 impl UnsafeCode {
309     fn report_unsafe(
310         &self,
311         cx: &EarlyContext<'_>,
312         span: Span,
313         decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
314     ) {
315         // This comes from a macro that has `#[allow_internal_unsafe]`.
316         if span.allows_unsafe() {
317             return;
318         }
319
320         cx.struct_span_lint(UNSAFE_CODE, span, decorate);
321     }
322
323     fn report_overridden_symbol_name(
324         &self,
325         cx: &EarlyContext<'_>,
326         span: Span,
327         msg: DiagnosticMessage,
328     ) {
329         self.report_unsafe(cx, span, |lint| {
330             lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
331         })
332     }
333
334     fn report_overridden_symbol_section(
335         &self,
336         cx: &EarlyContext<'_>,
337         span: Span,
338         msg: DiagnosticMessage,
339     ) {
340         self.report_unsafe(cx, span, |lint| {
341             lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
342         })
343     }
344 }
345
346 impl EarlyLintPass for UnsafeCode {
347     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
348         if attr.has_name(sym::allow_internal_unsafe) {
349             self.report_unsafe(cx, attr.span, |lint| {
350                 lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
351             });
352         }
353     }
354
355     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
356         if let ast::ExprKind::Block(ref blk, _) = e.kind {
357             // Don't warn about generated blocks; that'll just pollute the output.
358             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
359                 self.report_unsafe(cx, blk.span, |lint| {
360                     lint.build(fluent::lint::builtin_unsafe_block).emit();
361                 });
362             }
363         }
364     }
365
366     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
367         match it.kind {
368             ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
369                 .report_unsafe(cx, it.span, |lint| {
370                     lint.build(fluent::lint::builtin_unsafe_trait).emit();
371                 }),
372
373             ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
374                 .report_unsafe(cx, it.span, |lint| {
375                     lint.build(fluent::lint::builtin_unsafe_impl).emit();
376                 }),
377
378             ast::ItemKind::Fn(..) => {
379                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
380                     self.report_overridden_symbol_name(
381                         cx,
382                         attr.span,
383                         fluent::lint::builtin_no_mangle_fn,
384                     );
385                 }
386
387                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
388                     self.report_overridden_symbol_name(
389                         cx,
390                         attr.span,
391                         fluent::lint::builtin_export_name_fn,
392                     );
393                 }
394
395                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
396                     self.report_overridden_symbol_section(
397                         cx,
398                         attr.span,
399                         fluent::lint::builtin_link_section_fn,
400                     );
401                 }
402             }
403
404             ast::ItemKind::Static(..) => {
405                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
406                     self.report_overridden_symbol_name(
407                         cx,
408                         attr.span,
409                         fluent::lint::builtin_no_mangle_static,
410                     );
411                 }
412
413                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
414                     self.report_overridden_symbol_name(
415                         cx,
416                         attr.span,
417                         fluent::lint::builtin_export_name_static,
418                     );
419                 }
420
421                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
422                     self.report_overridden_symbol_section(
423                         cx,
424                         attr.span,
425                         fluent::lint::builtin_link_section_static,
426                     );
427                 }
428             }
429
430             _ => {}
431         }
432     }
433
434     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
435         if let ast::AssocItemKind::Fn(..) = it.kind {
436             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
437                 self.report_overridden_symbol_name(
438                     cx,
439                     attr.span,
440                     fluent::lint::builtin_no_mangle_method,
441                 );
442             }
443             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
444                 self.report_overridden_symbol_name(
445                     cx,
446                     attr.span,
447                     fluent::lint::builtin_export_name_method,
448                 );
449             }
450         }
451     }
452
453     fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
454         if let FnKind::Fn(
455             ctxt,
456             _,
457             ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
458             _,
459             _,
460             body,
461         ) = fk
462         {
463             let msg = match ctxt {
464                 FnCtxt::Foreign => return,
465                 FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
466                 FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
467                 FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
468             };
469             self.report_unsafe(cx, span, |lint| {
470                 lint.build(msg).emit();
471             });
472         }
473     }
474 }
475
476 declare_lint! {
477     /// The `missing_docs` lint detects missing documentation for public items.
478     ///
479     /// ### Example
480     ///
481     /// ```rust,compile_fail
482     /// #![deny(missing_docs)]
483     /// pub fn foo() {}
484     /// ```
485     ///
486     /// {{produces}}
487     ///
488     /// ### Explanation
489     ///
490     /// This lint is intended to ensure that a library is well-documented.
491     /// Items without documentation can be difficult for users to understand
492     /// how to use properly.
493     ///
494     /// This lint is "allow" by default because it can be noisy, and not all
495     /// projects may want to enforce everything to be documented.
496     pub MISSING_DOCS,
497     Allow,
498     "detects missing documentation for public members",
499     report_in_external_macro
500 }
501
502 pub struct MissingDoc {
503     /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
504     doc_hidden_stack: Vec<bool>,
505 }
506
507 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
508
509 fn has_doc(attr: &ast::Attribute) -> bool {
510     if attr.is_doc_comment() {
511         return true;
512     }
513
514     if !attr.has_name(sym::doc) {
515         return false;
516     }
517
518     if attr.value_str().is_some() {
519         return true;
520     }
521
522     if let Some(list) = attr.meta_item_list() {
523         for meta in list {
524             if meta.has_name(sym::hidden) {
525                 return true;
526             }
527         }
528     }
529
530     false
531 }
532
533 impl MissingDoc {
534     pub fn new() -> MissingDoc {
535         MissingDoc { doc_hidden_stack: vec![false] }
536     }
537
538     fn doc_hidden(&self) -> bool {
539         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
540     }
541
542     fn check_missing_docs_attrs(
543         &self,
544         cx: &LateContext<'_>,
545         def_id: LocalDefId,
546         article: &'static str,
547         desc: &'static str,
548     ) {
549         // If we're building a test harness, then warning about
550         // documentation is probably not really relevant right now.
551         if cx.sess().opts.test {
552             return;
553         }
554
555         // `#[doc(hidden)]` disables missing_docs check.
556         if self.doc_hidden() {
557             return;
558         }
559
560         // Only check publicly-visible items, using the result from the privacy pass.
561         // It's an option so the crate root can also use this function (it doesn't
562         // have a `NodeId`).
563         if def_id != CRATE_DEF_ID {
564             if !cx.access_levels.is_exported(def_id) {
565                 return;
566             }
567         }
568
569         let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
570         let has_doc = attrs.iter().any(has_doc);
571         if !has_doc {
572             cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
573                 lint.build(fluent::lint::builtin_missing_doc)
574                     .set_arg("article", article)
575                     .set_arg("desc", desc)
576                     .emit();
577             });
578         }
579     }
580 }
581
582 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
583     fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
584         let doc_hidden = self.doc_hidden()
585             || attrs.iter().any(|attr| {
586                 attr.has_name(sym::doc)
587                     && match attr.meta_item_list() {
588                         None => false,
589                         Some(l) => attr::list_contains_name(&l, sym::hidden),
590                     }
591             });
592         self.doc_hidden_stack.push(doc_hidden);
593     }
594
595     fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
596         self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
597     }
598
599     fn check_crate(&mut self, cx: &LateContext<'_>) {
600         self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
601     }
602
603     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
604         match it.kind {
605             hir::ItemKind::Trait(..) => {
606                 // Issue #11592: traits are always considered exported, even when private.
607                 if cx.tcx.visibility(it.def_id)
608                     == ty::Visibility::Restricted(
609                         cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(),
610                     )
611                 {
612                     return;
613                 }
614             }
615             hir::ItemKind::TyAlias(..)
616             | hir::ItemKind::Fn(..)
617             | hir::ItemKind::Macro(..)
618             | hir::ItemKind::Mod(..)
619             | hir::ItemKind::Enum(..)
620             | hir::ItemKind::Struct(..)
621             | hir::ItemKind::Union(..)
622             | hir::ItemKind::Const(..)
623             | hir::ItemKind::Static(..) => {}
624
625             _ => return,
626         };
627
628         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
629
630         self.check_missing_docs_attrs(cx, it.def_id.def_id, article, desc);
631     }
632
633     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
634         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
635
636         self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc);
637     }
638
639     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
640         // If the method is an impl for a trait, don't doc.
641         if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl {
642             return;
643         }
644
645         // If the method is an impl for an item with docs_hidden, don't doc.
646         if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
647             let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
648             let impl_ty = cx.tcx.type_of(parent);
649             let outerdef = match impl_ty.kind() {
650                 ty::Adt(def, _) => Some(def.did()),
651                 ty::Foreign(def_id) => Some(*def_id),
652                 _ => None,
653             };
654             let is_hidden = match outerdef {
655                 Some(id) => cx.tcx.is_doc_hidden(id),
656                 None => false,
657             };
658             if is_hidden {
659                 return;
660             }
661         }
662
663         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
664         self.check_missing_docs_attrs(cx, impl_item.def_id.def_id, article, desc);
665     }
666
667     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
668         let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
669         self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc);
670     }
671
672     fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
673         if !sf.is_positional() {
674             let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
675             self.check_missing_docs_attrs(cx, def_id, "a", "struct field")
676         }
677     }
678
679     fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
680         self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), "a", "variant");
681     }
682 }
683
684 declare_lint! {
685     /// The `missing_copy_implementations` lint detects potentially-forgotten
686     /// implementations of [`Copy`].
687     ///
688     /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
689     ///
690     /// ### Example
691     ///
692     /// ```rust,compile_fail
693     /// #![deny(missing_copy_implementations)]
694     /// pub struct Foo {
695     ///     pub field: i32
696     /// }
697     /// # fn main() {}
698     /// ```
699     ///
700     /// {{produces}}
701     ///
702     /// ### Explanation
703     ///
704     /// Historically (before 1.0), types were automatically marked as `Copy`
705     /// if possible. This was changed so that it required an explicit opt-in
706     /// by implementing the `Copy` trait. As part of this change, a lint was
707     /// added to alert if a copyable type was not marked `Copy`.
708     ///
709     /// This lint is "allow" by default because this code isn't bad; it is
710     /// common to write newtypes like this specifically so that a `Copy` type
711     /// is no longer `Copy`. `Copy` types can result in unintended copies of
712     /// large data which can impact performance.
713     pub MISSING_COPY_IMPLEMENTATIONS,
714     Allow,
715     "detects potentially-forgotten implementations of `Copy`"
716 }
717
718 declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
719
720 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
721     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
722         if !cx.access_levels.is_reachable(item.def_id.def_id) {
723             return;
724         }
725         let (def, ty) = match item.kind {
726             hir::ItemKind::Struct(_, ref ast_generics) => {
727                 if !ast_generics.params.is_empty() {
728                     return;
729                 }
730                 let def = cx.tcx.adt_def(item.def_id);
731                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
732             }
733             hir::ItemKind::Union(_, ref ast_generics) => {
734                 if !ast_generics.params.is_empty() {
735                     return;
736                 }
737                 let def = cx.tcx.adt_def(item.def_id);
738                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
739             }
740             hir::ItemKind::Enum(_, ref ast_generics) => {
741                 if !ast_generics.params.is_empty() {
742                     return;
743                 }
744                 let def = cx.tcx.adt_def(item.def_id);
745                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
746             }
747             _ => return,
748         };
749         if def.has_dtor(cx.tcx) {
750             return;
751         }
752         let param_env = ty::ParamEnv::empty();
753         if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
754             return;
755         }
756         if can_type_implement_copy(
757             cx.tcx,
758             param_env,
759             ty,
760             traits::ObligationCause::misc(item.span, item.hir_id()),
761         )
762         .is_ok()
763         {
764             cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
765                 lint.build(fluent::lint::builtin_missing_copy_impl).emit();
766             })
767         }
768     }
769 }
770
771 declare_lint! {
772     /// The `missing_debug_implementations` lint detects missing
773     /// implementations of [`fmt::Debug`].
774     ///
775     /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
776     ///
777     /// ### Example
778     ///
779     /// ```rust,compile_fail
780     /// #![deny(missing_debug_implementations)]
781     /// pub struct Foo;
782     /// # fn main() {}
783     /// ```
784     ///
785     /// {{produces}}
786     ///
787     /// ### Explanation
788     ///
789     /// Having a `Debug` implementation on all types can assist with
790     /// debugging, as it provides a convenient way to format and display a
791     /// value. Using the `#[derive(Debug)]` attribute will automatically
792     /// generate a typical implementation, or a custom implementation can be
793     /// added by manually implementing the `Debug` trait.
794     ///
795     /// This lint is "allow" by default because adding `Debug` to all types can
796     /// have a negative impact on compile time and code size. It also requires
797     /// boilerplate to be added to every type, which can be an impediment.
798     MISSING_DEBUG_IMPLEMENTATIONS,
799     Allow,
800     "detects missing implementations of Debug"
801 }
802
803 #[derive(Default)]
804 pub struct MissingDebugImplementations {
805     impling_types: Option<LocalDefIdSet>,
806 }
807
808 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
809
810 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
811     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
812         if !cx.access_levels.is_reachable(item.def_id.def_id) {
813             return;
814         }
815
816         match item.kind {
817             hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
818             _ => return,
819         }
820
821         let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
822             return
823         };
824
825         if self.impling_types.is_none() {
826             let mut impls = LocalDefIdSet::default();
827             cx.tcx.for_each_impl(debug, |d| {
828                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
829                     if let Some(def_id) = ty_def.did().as_local() {
830                         impls.insert(def_id);
831                     }
832                 }
833             });
834
835             self.impling_types = Some(impls);
836             debug!("{:?}", self.impling_types);
837         }
838
839         if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
840             cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
841                 lint.build(fluent::lint::builtin_missing_debug_impl)
842                     .set_arg("debug", cx.tcx.def_path_str(debug))
843                     .emit();
844             });
845         }
846     }
847 }
848
849 declare_lint! {
850     /// The `anonymous_parameters` lint detects anonymous parameters in trait
851     /// definitions.
852     ///
853     /// ### Example
854     ///
855     /// ```rust,edition2015,compile_fail
856     /// #![deny(anonymous_parameters)]
857     /// // edition 2015
858     /// pub trait Foo {
859     ///     fn foo(usize);
860     /// }
861     /// fn main() {}
862     /// ```
863     ///
864     /// {{produces}}
865     ///
866     /// ### Explanation
867     ///
868     /// This syntax is mostly a historical accident, and can be worked around
869     /// quite easily by adding an `_` pattern or a descriptive identifier:
870     ///
871     /// ```rust
872     /// trait Foo {
873     ///     fn foo(_: usize);
874     /// }
875     /// ```
876     ///
877     /// This syntax is now a hard error in the 2018 edition. In the 2015
878     /// edition, this lint is "warn" by default. This lint
879     /// enables the [`cargo fix`] tool with the `--edition` flag to
880     /// automatically transition old code from the 2015 edition to 2018. The
881     /// tool will run this lint and automatically apply the
882     /// suggested fix from the compiler (which is to add `_` to each
883     /// parameter). This provides a completely automated way to update old
884     /// code for a new edition. See [issue #41686] for more details.
885     ///
886     /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
887     /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
888     pub ANONYMOUS_PARAMETERS,
889     Warn,
890     "detects anonymous parameters",
891     @future_incompatible = FutureIncompatibleInfo {
892         reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
893         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
894     };
895 }
896
897 declare_lint_pass!(
898     /// Checks for use of anonymous parameters (RFC 1685).
899     AnonymousParameters => [ANONYMOUS_PARAMETERS]
900 );
901
902 impl EarlyLintPass for AnonymousParameters {
903     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
904         if cx.sess().edition() != Edition::Edition2015 {
905             // This is a hard error in future editions; avoid linting and erroring
906             return;
907         }
908         if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
909             for arg in sig.decl.inputs.iter() {
910                 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
911                     if ident.name == kw::Empty {
912                         cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
913                             let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
914
915                             let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
916                                 (snip.as_str(), Applicability::MachineApplicable)
917                             } else {
918                                 ("<type>", Applicability::HasPlaceholders)
919                             };
920
921                             lint.build(fluent::lint::builtin_anonymous_params)
922                                 .span_suggestion(
923                                     arg.pat.span,
924                                     fluent::lint::suggestion,
925                                     format!("_: {}", ty_snip),
926                                     appl,
927                                 )
928                                 .emit();
929                         })
930                     }
931                 }
932             }
933         }
934     }
935 }
936
937 /// Check for use of attributes which have been deprecated.
938 #[derive(Clone)]
939 pub struct DeprecatedAttr {
940     // This is not free to compute, so we want to keep it around, rather than
941     // compute it for every attribute.
942     depr_attrs: Vec<&'static BuiltinAttribute>,
943 }
944
945 impl_lint_pass!(DeprecatedAttr => []);
946
947 impl DeprecatedAttr {
948     pub fn new() -> DeprecatedAttr {
949         DeprecatedAttr { depr_attrs: deprecated_attributes() }
950     }
951 }
952
953 impl EarlyLintPass for DeprecatedAttr {
954     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
955         for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
956             if attr.ident().map(|ident| ident.name) == Some(*name) {
957                 if let &AttributeGate::Gated(
958                     Stability::Deprecated(link, suggestion),
959                     name,
960                     reason,
961                     _,
962                 ) = gate
963                 {
964                     cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
965                         // FIXME(davidtwco) translatable deprecated attr
966                         lint.build(fluent::lint::builtin_deprecated_attr_link)
967                             .set_arg("name", name)
968                             .set_arg("reason", reason)
969                             .set_arg("link", link)
970                             .span_suggestion_short(
971                                 attr.span,
972                                 suggestion.map(|s| s.into()).unwrap_or(
973                                     fluent::lint::builtin_deprecated_attr_default_suggestion,
974                                 ),
975                                 "",
976                                 Applicability::MachineApplicable,
977                             )
978                             .emit();
979                     });
980                 }
981                 return;
982             }
983         }
984         if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
985             cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
986                 lint.build(fluent::lint::builtin_deprecated_attr_used)
987                     .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
988                     .span_suggestion_short(
989                         attr.span,
990                         fluent::lint::builtin_deprecated_attr_default_suggestion,
991                         "",
992                         Applicability::MachineApplicable,
993                     )
994                     .emit();
995             });
996         }
997     }
998 }
999
1000 fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
1001     use rustc_ast::token::CommentKind;
1002
1003     let mut attrs = attrs.iter().peekable();
1004
1005     // Accumulate a single span for sugared doc comments.
1006     let mut sugared_span: Option<Span> = None;
1007
1008     while let Some(attr) = attrs.next() {
1009         let is_doc_comment = attr.is_doc_comment();
1010         if is_doc_comment {
1011             sugared_span =
1012                 Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
1013         }
1014
1015         if attrs.peek().map_or(false, |next_attr| next_attr.is_doc_comment()) {
1016             continue;
1017         }
1018
1019         let span = sugared_span.take().unwrap_or(attr.span);
1020
1021         if is_doc_comment || attr.has_name(sym::doc) {
1022             cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
1023                 let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
1024                 err.set_arg("kind", node_kind);
1025                 err.span_label(node_span, fluent::lint::label);
1026                 match attr.kind {
1027                     AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
1028                         err.help(fluent::lint::plain_help);
1029                     }
1030                     AttrKind::DocComment(CommentKind::Block, _) => {
1031                         err.help(fluent::lint::block_help);
1032                     }
1033                 }
1034                 err.emit();
1035             });
1036         }
1037     }
1038 }
1039
1040 impl EarlyLintPass for UnusedDocComment {
1041     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
1042         let kind = match stmt.kind {
1043             ast::StmtKind::Local(..) => "statements",
1044             // Disabled pending discussion in #78306
1045             ast::StmtKind::Item(..) => return,
1046             // expressions will be reported by `check_expr`.
1047             ast::StmtKind::Empty
1048             | ast::StmtKind::Semi(_)
1049             | ast::StmtKind::Expr(_)
1050             | ast::StmtKind::MacCall(_) => return,
1051         };
1052
1053         warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
1054     }
1055
1056     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1057         let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
1058         warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1059     }
1060
1061     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1062         warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
1063     }
1064
1065     fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
1066         warn_if_doc(cx, param.ident.span, "generic parameters", &param.attrs);
1067     }
1068
1069     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
1070         warn_if_doc(cx, block.span, "blocks", &block.attrs());
1071     }
1072
1073     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1074         if let ast::ItemKind::ForeignMod(_) = item.kind {
1075             warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
1076         }
1077     }
1078 }
1079
1080 declare_lint! {
1081     /// The `no_mangle_const_items` lint detects any `const` items with the
1082     /// [`no_mangle` attribute].
1083     ///
1084     /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1085     ///
1086     /// ### Example
1087     ///
1088     /// ```rust,compile_fail
1089     /// #[no_mangle]
1090     /// const FOO: i32 = 5;
1091     /// ```
1092     ///
1093     /// {{produces}}
1094     ///
1095     /// ### Explanation
1096     ///
1097     /// Constants do not have their symbols exported, and therefore, this
1098     /// probably means you meant to use a [`static`], not a [`const`].
1099     ///
1100     /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
1101     /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
1102     NO_MANGLE_CONST_ITEMS,
1103     Deny,
1104     "const items will not have their symbols exported"
1105 }
1106
1107 declare_lint! {
1108     /// The `no_mangle_generic_items` lint detects generic items that must be
1109     /// mangled.
1110     ///
1111     /// ### Example
1112     ///
1113     /// ```rust
1114     /// #[no_mangle]
1115     /// fn foo<T>(t: T) {
1116     ///
1117     /// }
1118     /// ```
1119     ///
1120     /// {{produces}}
1121     ///
1122     /// ### Explanation
1123     ///
1124     /// A function with generics must have its symbol mangled to accommodate
1125     /// the generic parameter. The [`no_mangle` attribute] has no effect in
1126     /// this situation, and should be removed.
1127     ///
1128     /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1129     NO_MANGLE_GENERIC_ITEMS,
1130     Warn,
1131     "generic items must be mangled"
1132 }
1133
1134 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
1135
1136 impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
1137     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1138         let attrs = cx.tcx.hir().attrs(it.hir_id());
1139         let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute,
1140                                              impl_generics: Option<&hir::Generics<'_>>,
1141                                              generics: &hir::Generics<'_>,
1142                                              span| {
1143             for param in
1144                 generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1145             {
1146                 match param.kind {
1147                     GenericParamKind::Lifetime { .. } => {}
1148                     GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1149                         cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
1150                             lint.build(fluent::lint::builtin_no_mangle_generic)
1151                                 .span_suggestion_short(
1152                                     no_mangle_attr.span,
1153                                     fluent::lint::suggestion,
1154                                     "",
1155                                     // Use of `#[no_mangle]` suggests FFI intent; correct
1156                                     // fix may be to monomorphize source by hand
1157                                     Applicability::MaybeIncorrect,
1158                                 )
1159                                 .emit();
1160                         });
1161                         break;
1162                     }
1163                 }
1164             }
1165         };
1166         match it.kind {
1167             hir::ItemKind::Fn(.., ref generics, _) => {
1168                 if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
1169                     check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
1170                 }
1171             }
1172             hir::ItemKind::Const(..) => {
1173                 if cx.sess().contains_name(attrs, sym::no_mangle) {
1174                     // Const items do not refer to a particular location in memory, and therefore
1175                     // don't have anything to attach a symbol to
1176                     cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
1177                         let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
1178
1179                         // account for "pub const" (#45562)
1180                         let start = cx
1181                             .tcx
1182                             .sess
1183                             .source_map()
1184                             .span_to_snippet(it.span)
1185                             .map(|snippet| snippet.find("const").unwrap_or(0))
1186                             .unwrap_or(0) as u32;
1187                         // `const` is 5 chars
1188                         let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1189                         err.span_suggestion(
1190                             const_span,
1191                             fluent::lint::suggestion,
1192                             "pub static",
1193                             Applicability::MachineApplicable,
1194                         );
1195                         err.emit();
1196                     });
1197                 }
1198             }
1199             hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1200                 for it in *items {
1201                     if let hir::AssocItemKind::Fn { .. } = it.kind {
1202                         if let Some(no_mangle_attr) = cx
1203                             .sess()
1204                             .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
1205                         {
1206                             check_no_mangle_on_generic_fn(
1207                                 no_mangle_attr,
1208                                 Some(generics),
1209                                 cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(),
1210                                 it.span,
1211                             );
1212                         }
1213                     }
1214                 }
1215             }
1216             _ => {}
1217         }
1218     }
1219 }
1220
1221 declare_lint! {
1222     /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1223     /// T` because it is [undefined behavior].
1224     ///
1225     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1226     ///
1227     /// ### Example
1228     ///
1229     /// ```rust,compile_fail
1230     /// unsafe {
1231     ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);
1232     /// }
1233     /// ```
1234     ///
1235     /// {{produces}}
1236     ///
1237     /// ### Explanation
1238     ///
1239     /// Certain assumptions are made about aliasing of data, and this transmute
1240     /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1241     ///
1242     /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1243     MUTABLE_TRANSMUTES,
1244     Deny,
1245     "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1246 }
1247
1248 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1249
1250 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1251     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1252         if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
1253             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1254         {
1255             if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
1256                 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
1257                     lint.build(fluent::lint::builtin_mutable_transmutes).emit();
1258                 });
1259             }
1260         }
1261
1262         fn get_transmute_from_to<'tcx>(
1263             cx: &LateContext<'tcx>,
1264             expr: &hir::Expr<'_>,
1265         ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1266             let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1267                 cx.qpath_res(qpath, expr.hir_id)
1268             } else {
1269                 return None;
1270             };
1271             if let Res::Def(DefKind::Fn, did) = def {
1272                 if !def_id_is_transmute(cx, did) {
1273                     return None;
1274                 }
1275                 let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1276                 let from = sig.inputs().skip_binder()[0];
1277                 let to = sig.output().skip_binder();
1278                 return Some((from, to));
1279             }
1280             None
1281         }
1282
1283         fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1284             cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
1285         }
1286     }
1287 }
1288
1289 declare_lint! {
1290     /// The `unstable_features` is deprecated and should no longer be used.
1291     UNSTABLE_FEATURES,
1292     Allow,
1293     "enabling unstable features (deprecated. do not use)"
1294 }
1295
1296 declare_lint_pass!(
1297     /// Forbids using the `#[feature(...)]` attribute
1298     UnstableFeatures => [UNSTABLE_FEATURES]
1299 );
1300
1301 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1302     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
1303         if attr.has_name(sym::feature) {
1304             if let Some(items) = attr.meta_item_list() {
1305                 for item in items {
1306                     cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
1307                         lint.build(fluent::lint::builtin_unstable_features).emit();
1308                     });
1309                 }
1310             }
1311         }
1312     }
1313 }
1314
1315 declare_lint! {
1316     /// The `unreachable_pub` lint triggers for `pub` items not reachable from
1317     /// the crate root.
1318     ///
1319     /// ### Example
1320     ///
1321     /// ```rust,compile_fail
1322     /// #![deny(unreachable_pub)]
1323     /// mod foo {
1324     ///     pub mod bar {
1325     ///
1326     ///     }
1327     /// }
1328     /// ```
1329     ///
1330     /// {{produces}}
1331     ///
1332     /// ### Explanation
1333     ///
1334     /// A bare `pub` visibility may be misleading if the item is not actually
1335     /// publicly exported from the crate. The `pub(crate)` visibility is
1336     /// recommended to be used instead, which more clearly expresses the intent
1337     /// that the item is only visible within its own crate.
1338     ///
1339     /// This lint is "allow" by default because it will trigger for a large
1340     /// amount existing Rust code, and has some false-positives. Eventually it
1341     /// is desired for this to become warn-by-default.
1342     pub UNREACHABLE_PUB,
1343     Allow,
1344     "`pub` items not reachable from crate root"
1345 }
1346
1347 declare_lint_pass!(
1348     /// Lint for items marked `pub` that aren't reachable from other crates.
1349     UnreachablePub => [UNREACHABLE_PUB]
1350 );
1351
1352 impl UnreachablePub {
1353     fn perform_lint(
1354         &self,
1355         cx: &LateContext<'_>,
1356         what: &str,
1357         def_id: LocalDefId,
1358         vis_span: Span,
1359         exportable: bool,
1360     ) {
1361         let mut applicability = Applicability::MachineApplicable;
1362         if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
1363             if vis_span.from_expansion() {
1364                 applicability = Applicability::MaybeIncorrect;
1365             }
1366             let def_span = cx.tcx.def_span(def_id);
1367             cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
1368                 let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
1369                 err.set_arg("what", what);
1370
1371                 err.span_suggestion(
1372                     vis_span,
1373                     fluent::lint::suggestion,
1374                     "pub(crate)",
1375                     applicability,
1376                 );
1377                 if exportable {
1378                     err.help(fluent::lint::help);
1379                 }
1380                 err.emit();
1381             });
1382         }
1383     }
1384 }
1385
1386 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1387     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1388         // Do not warn for fake `use` statements.
1389         if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1390             return;
1391         }
1392         self.perform_lint(cx, "item", item.def_id.def_id, item.vis_span, true);
1393     }
1394
1395     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
1396         self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true);
1397     }
1398
1399     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
1400         let def_id = cx.tcx.hir().local_def_id(field.hir_id);
1401         self.perform_lint(cx, "field", def_id, field.vis_span, false);
1402     }
1403
1404     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
1405         // Only lint inherent impl items.
1406         if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
1407             self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false);
1408         }
1409     }
1410 }
1411
1412 declare_lint! {
1413     /// The `type_alias_bounds` lint detects bounds in type aliases.
1414     ///
1415     /// ### Example
1416     ///
1417     /// ```rust
1418     /// type SendVec<T: Send> = Vec<T>;
1419     /// ```
1420     ///
1421     /// {{produces}}
1422     ///
1423     /// ### Explanation
1424     ///
1425     /// The trait bounds in a type alias are currently ignored, and should not
1426     /// be included to avoid confusion. This was previously allowed
1427     /// unintentionally; this may become a hard error in the future.
1428     TYPE_ALIAS_BOUNDS,
1429     Warn,
1430     "bounds in type aliases are not enforced"
1431 }
1432
1433 declare_lint_pass!(
1434     /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1435     /// They are relevant when using associated types, but otherwise neither checked
1436     /// at definition site nor enforced at use site.
1437     TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1438 );
1439
1440 impl TypeAliasBounds {
1441     fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
1442         match *qpath {
1443             hir::QPath::TypeRelative(ref ty, _) => {
1444                 // If this is a type variable, we found a `T::Assoc`.
1445                 match ty.kind {
1446                     hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
1447                         matches!(path.res, Res::Def(DefKind::TyParam, _))
1448                     }
1449                     _ => false,
1450                 }
1451             }
1452             hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
1453         }
1454     }
1455
1456     fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) {
1457         // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1458         // bound.  Let's see if this type does that.
1459
1460         // We use a HIR visitor to walk the type.
1461         use rustc_hir::intravisit::{self, Visitor};
1462         struct WalkAssocTypes<'a> {
1463             err: &'a mut Diagnostic,
1464         }
1465         impl Visitor<'_> for WalkAssocTypes<'_> {
1466             fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
1467                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
1468                     self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
1469                 }
1470                 intravisit::walk_qpath(self, qpath, id)
1471             }
1472         }
1473
1474         // Let's go for a walk!
1475         let mut visitor = WalkAssocTypes { err };
1476         visitor.visit_ty(ty);
1477     }
1478 }
1479
1480 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1481     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1482         let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
1483             return
1484         };
1485         if let hir::TyKind::OpaqueDef(..) = ty.kind {
1486             // Bounds are respected for `type X = impl Trait`
1487             return;
1488         }
1489         // There must not be a where clause
1490         if type_alias_generics.predicates.is_empty() {
1491             return;
1492         }
1493
1494         let mut where_spans = Vec::new();
1495         let mut inline_spans = Vec::new();
1496         let mut inline_sugg = Vec::new();
1497         for p in type_alias_generics.predicates {
1498             let span = p.span();
1499             if p.in_where_clause() {
1500                 where_spans.push(span);
1501             } else {
1502                 for b in p.bounds() {
1503                     inline_spans.push(b.span());
1504                 }
1505                 inline_sugg.push((span, String::new()));
1506             }
1507         }
1508
1509         let mut suggested_changing_assoc_types = false;
1510         if !where_spans.is_empty() {
1511             cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1512                 let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
1513                 err.set_span(where_spans);
1514                 err.span_suggestion(
1515                     type_alias_generics.where_clause_span,
1516                     fluent::lint::suggestion,
1517                     "",
1518                     Applicability::MachineApplicable,
1519                 );
1520                 if !suggested_changing_assoc_types {
1521                     TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1522                     suggested_changing_assoc_types = true;
1523                 }
1524                 err.emit();
1525             });
1526         }
1527
1528         if !inline_spans.is_empty() {
1529             cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1530                 let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
1531                 err.set_span(inline_spans);
1532                 err.multipart_suggestion(
1533                     fluent::lint::suggestion,
1534                     inline_sugg,
1535                     Applicability::MachineApplicable,
1536                 );
1537                 if !suggested_changing_assoc_types {
1538                     TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1539                 }
1540                 err.emit();
1541             });
1542         }
1543     }
1544 }
1545
1546 declare_lint_pass!(
1547     /// Lint constants that are erroneous.
1548     /// Without this lint, we might not get any diagnostic if the constant is
1549     /// unused within this crate, even though downstream crates can't use it
1550     /// without producing an error.
1551     UnusedBrokenConst => []
1552 );
1553
1554 impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
1555     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1556         match it.kind {
1557             hir::ItemKind::Const(_, body_id) => {
1558                 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1559                 // trigger the query once for all constants since that will already report the errors
1560                 cx.tcx.ensure().const_eval_poly(def_id);
1561             }
1562             hir::ItemKind::Static(_, _, body_id) => {
1563                 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1564                 cx.tcx.ensure().eval_static_initializer(def_id);
1565             }
1566             _ => {}
1567         }
1568     }
1569 }
1570
1571 declare_lint! {
1572     /// The `trivial_bounds` lint detects trait bounds that don't depend on
1573     /// any type parameters.
1574     ///
1575     /// ### Example
1576     ///
1577     /// ```rust
1578     /// #![feature(trivial_bounds)]
1579     /// pub struct A where i32: Copy;
1580     /// ```
1581     ///
1582     /// {{produces}}
1583     ///
1584     /// ### Explanation
1585     ///
1586     /// Usually you would not write a trait bound that you know is always
1587     /// true, or never true. However, when using macros, the macro may not
1588     /// know whether or not the constraint would hold or not at the time when
1589     /// generating the code. Currently, the compiler does not alert you if the
1590     /// constraint is always true, and generates an error if it is never true.
1591     /// The `trivial_bounds` feature changes this to be a warning in both
1592     /// cases, giving macros more freedom and flexibility to generate code,
1593     /// while still providing a signal when writing non-macro code that
1594     /// something is amiss.
1595     ///
1596     /// See [RFC 2056] for more details. This feature is currently only
1597     /// available on the nightly channel, see [tracking issue #48214].
1598     ///
1599     /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1600     /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1601     TRIVIAL_BOUNDS,
1602     Warn,
1603     "these bounds don't depend on an type parameters"
1604 }
1605
1606 declare_lint_pass!(
1607     /// Lint for trait and lifetime bounds that don't depend on type parameters
1608     /// which either do nothing, or stop the item from being used.
1609     TrivialConstraints => [TRIVIAL_BOUNDS]
1610 );
1611
1612 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1613     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1614         use rustc_middle::ty::visit::TypeVisitable;
1615         use rustc_middle::ty::PredicateKind::*;
1616
1617         if cx.tcx.features().trivial_bounds {
1618             let predicates = cx.tcx.predicates_of(item.def_id);
1619             for &(predicate, span) in predicates.predicates {
1620                 let predicate_kind_name = match predicate.kind().skip_binder() {
1621                     Trait(..) => "trait",
1622                     TypeOutlives(..) |
1623                     RegionOutlives(..) => "lifetime",
1624
1625                     // Ignore projections, as they can only be global
1626                     // if the trait bound is global
1627                     Projection(..) |
1628                     // Ignore bounds that a user can't type
1629                     WellFormed(..) |
1630                     ObjectSafe(..) |
1631                     ClosureKind(..) |
1632                     Subtype(..) |
1633                     Coerce(..) |
1634                     ConstEvaluatable(..) |
1635                     ConstEquate(..) |
1636                     TypeWellFormedFromEnv(..) => continue,
1637                 };
1638                 if predicate.is_global() {
1639                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
1640                         lint.build(fluent::lint::builtin_trivial_bounds)
1641                             .set_arg("predicate_kind_name", predicate_kind_name)
1642                             .set_arg("predicate", predicate)
1643                             .emit();
1644                     });
1645                 }
1646             }
1647         }
1648     }
1649 }
1650
1651 declare_lint_pass!(
1652     /// Does nothing as a lint pass, but registers some `Lint`s
1653     /// which are used by other parts of the compiler.
1654     SoftLints => [
1655         WHILE_TRUE,
1656         BOX_POINTERS,
1657         NON_SHORTHAND_FIELD_PATTERNS,
1658         UNSAFE_CODE,
1659         MISSING_DOCS,
1660         MISSING_COPY_IMPLEMENTATIONS,
1661         MISSING_DEBUG_IMPLEMENTATIONS,
1662         ANONYMOUS_PARAMETERS,
1663         UNUSED_DOC_COMMENTS,
1664         NO_MANGLE_CONST_ITEMS,
1665         NO_MANGLE_GENERIC_ITEMS,
1666         MUTABLE_TRANSMUTES,
1667         UNSTABLE_FEATURES,
1668         UNREACHABLE_PUB,
1669         TYPE_ALIAS_BOUNDS,
1670         TRIVIAL_BOUNDS
1671     ]
1672 );
1673
1674 declare_lint! {
1675     /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1676     /// pattern], which is deprecated.
1677     ///
1678     /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1679     ///
1680     /// ### Example
1681     ///
1682     /// ```rust,edition2018
1683     /// let x = 123;
1684     /// match x {
1685     ///     0...100 => {}
1686     ///     _ => {}
1687     /// }
1688     /// ```
1689     ///
1690     /// {{produces}}
1691     ///
1692     /// ### Explanation
1693     ///
1694     /// The `...` range pattern syntax was changed to `..=` to avoid potential
1695     /// confusion with the [`..` range expression]. Use the new form instead.
1696     ///
1697     /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1698     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1699     Warn,
1700     "`...` range patterns are deprecated",
1701     @future_incompatible = FutureIncompatibleInfo {
1702         reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1703         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
1704     };
1705 }
1706
1707 #[derive(Default)]
1708 pub struct EllipsisInclusiveRangePatterns {
1709     /// If `Some(_)`, suppress all subsequent pattern
1710     /// warnings for better diagnostics.
1711     node_id: Option<ast::NodeId>,
1712 }
1713
1714 impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1715
1716 impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1717     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1718         if self.node_id.is_some() {
1719             // Don't recursively warn about patterns inside range endpoints.
1720             return;
1721         }
1722
1723         use self::ast::{PatKind, RangeSyntax::DotDotDot};
1724
1725         /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1726         /// corresponding to the ellipsis.
1727         fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1728             match &pat.kind {
1729                 PatKind::Range(
1730                     a,
1731                     Some(b),
1732                     Spanned { span, node: RangeEnd::Included(DotDotDot) },
1733                 ) => Some((a.as_deref(), b, *span)),
1734                 _ => None,
1735             }
1736         }
1737
1738         let (parenthesise, endpoints) = match &pat.kind {
1739             PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
1740             _ => (false, matches_ellipsis_pat(pat)),
1741         };
1742
1743         if let Some((start, end, join)) = endpoints {
1744             let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
1745             let suggestion = fluent::lint::suggestion;
1746             if parenthesise {
1747                 self.node_id = Some(pat.id);
1748                 let end = expr_to_string(&end);
1749                 let replace = match start {
1750                     Some(start) => format!("&({}..={})", expr_to_string(&start), end),
1751                     None => format!("&(..={})", end),
1752                 };
1753                 if join.edition() >= Edition::Edition2021 {
1754                     cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1755                         span: pat.span,
1756                         suggestion: pat.span,
1757                         replace,
1758                     });
1759                 } else {
1760                     cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
1761                         lint.build(msg)
1762                             .span_suggestion(
1763                                 pat.span,
1764                                 suggestion,
1765                                 replace,
1766                                 Applicability::MachineApplicable,
1767                             )
1768                             .emit();
1769                     });
1770                 }
1771             } else {
1772                 let replace = "..=";
1773                 if join.edition() >= Edition::Edition2021 {
1774                     cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1775                         span: pat.span,
1776                         suggestion: join,
1777                         replace: replace.to_string(),
1778                     });
1779                 } else {
1780                     cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
1781                         lint.build(msg)
1782                             .span_suggestion_short(
1783                                 join,
1784                                 suggestion,
1785                                 replace,
1786                                 Applicability::MachineApplicable,
1787                             )
1788                             .emit();
1789                     });
1790                 }
1791             };
1792         }
1793     }
1794
1795     fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1796         if let Some(node_id) = self.node_id {
1797             if pat.id == node_id {
1798                 self.node_id = None
1799             }
1800         }
1801     }
1802 }
1803
1804 declare_lint! {
1805     /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
1806     /// that are not able to be run by the test harness because they are in a
1807     /// position where they are not nameable.
1808     ///
1809     /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
1810     ///
1811     /// ### Example
1812     ///
1813     /// ```rust,test
1814     /// fn main() {
1815     ///     #[test]
1816     ///     fn foo() {
1817     ///         // This test will not fail because it does not run.
1818     ///         assert_eq!(1, 2);
1819     ///     }
1820     /// }
1821     /// ```
1822     ///
1823     /// {{produces}}
1824     ///
1825     /// ### Explanation
1826     ///
1827     /// In order for the test harness to run a test, the test function must be
1828     /// located in a position where it can be accessed from the crate root.
1829     /// This generally means it must be defined in a module, and not anywhere
1830     /// else such as inside another function. The compiler previously allowed
1831     /// this without an error, so a lint was added as an alert that a test is
1832     /// not being used. Whether or not this should be allowed has not yet been
1833     /// decided, see [RFC 2471] and [issue #36629].
1834     ///
1835     /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
1836     /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
1837     UNNAMEABLE_TEST_ITEMS,
1838     Warn,
1839     "detects an item that cannot be named being marked as `#[test_case]`",
1840     report_in_external_macro
1841 }
1842
1843 pub struct UnnameableTestItems {
1844     boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
1845     items_nameable: bool,
1846 }
1847
1848 impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1849
1850 impl UnnameableTestItems {
1851     pub fn new() -> Self {
1852         Self { boundary: None, items_nameable: true }
1853     }
1854 }
1855
1856 impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
1857     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1858         if self.items_nameable {
1859             if let hir::ItemKind::Mod(..) = it.kind {
1860             } else {
1861                 self.items_nameable = false;
1862                 self.boundary = Some(it.def_id);
1863             }
1864             return;
1865         }
1866
1867         let attrs = cx.tcx.hir().attrs(it.hir_id());
1868         if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
1869             cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
1870                 lint.build(fluent::lint::builtin_unnameable_test_items).emit();
1871             });
1872         }
1873     }
1874
1875     fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
1876         if !self.items_nameable && self.boundary == Some(it.def_id) {
1877             self.items_nameable = true;
1878         }
1879     }
1880 }
1881
1882 declare_lint! {
1883     /// The `keyword_idents` lint detects edition keywords being used as an
1884     /// identifier.
1885     ///
1886     /// ### Example
1887     ///
1888     /// ```rust,edition2015,compile_fail
1889     /// #![deny(keyword_idents)]
1890     /// // edition 2015
1891     /// fn dyn() {}
1892     /// ```
1893     ///
1894     /// {{produces}}
1895     ///
1896     /// ### Explanation
1897     ///
1898     /// Rust [editions] allow the language to evolve without breaking
1899     /// backwards compatibility. This lint catches code that uses new keywords
1900     /// that are added to the language that are used as identifiers (such as a
1901     /// variable name, function name, etc.). If you switch the compiler to a
1902     /// new edition without updating the code, then it will fail to compile if
1903     /// you are using a new keyword as an identifier.
1904     ///
1905     /// You can manually change the identifiers to a non-keyword, or use a
1906     /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1907     ///
1908     /// This lint solves the problem automatically. It is "allow" by default
1909     /// because the code is perfectly valid in older editions. The [`cargo
1910     /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1911     /// and automatically apply the suggested fix from the compiler (which is
1912     /// to use a raw identifier). This provides a completely automated way to
1913     /// update old code for a new edition.
1914     ///
1915     /// [editions]: https://doc.rust-lang.org/edition-guide/
1916     /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1917     /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1918     pub KEYWORD_IDENTS,
1919     Allow,
1920     "detects edition keywords being used as an identifier",
1921     @future_incompatible = FutureIncompatibleInfo {
1922         reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1923         reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
1924     };
1925 }
1926
1927 declare_lint_pass!(
1928     /// Check for uses of edition keywords used as an identifier.
1929     KeywordIdents => [KEYWORD_IDENTS]
1930 );
1931
1932 struct UnderMacro(bool);
1933
1934 impl KeywordIdents {
1935     fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
1936         for tt in tokens.into_trees() {
1937             match tt {
1938                 // Only report non-raw idents.
1939                 TokenTree::Token(token, _) => {
1940                     if let Some((ident, false)) = token.ident() {
1941                         self.check_ident_token(cx, UnderMacro(true), ident);
1942                     }
1943                 }
1944                 TokenTree::Delimited(_, _, tts) => self.check_tokens(cx, tts),
1945             }
1946         }
1947     }
1948
1949     fn check_ident_token(
1950         &mut self,
1951         cx: &EarlyContext<'_>,
1952         UnderMacro(under_macro): UnderMacro,
1953         ident: Ident,
1954     ) {
1955         let next_edition = match cx.sess().edition() {
1956             Edition::Edition2015 => {
1957                 match ident.name {
1958                     kw::Async | kw::Await | kw::Try => Edition::Edition2018,
1959
1960                     // rust-lang/rust#56327: Conservatively do not
1961                     // attempt to report occurrences of `dyn` within
1962                     // macro definitions or invocations, because `dyn`
1963                     // can legitimately occur as a contextual keyword
1964                     // in 2015 code denoting its 2018 meaning, and we
1965                     // do not want rustfix to inject bugs into working
1966                     // code by rewriting such occurrences.
1967                     //
1968                     // But if we see `dyn` outside of a macro, we know
1969                     // its precise role in the parsed AST and thus are
1970                     // assured this is truly an attempt to use it as
1971                     // an identifier.
1972                     kw::Dyn if !under_macro => Edition::Edition2018,
1973
1974                     _ => return,
1975                 }
1976             }
1977
1978             // There are no new keywords yet for the 2018 edition and beyond.
1979             _ => return,
1980         };
1981
1982         // Don't lint `r#foo`.
1983         if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1984             return;
1985         }
1986
1987         cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
1988             lint.build(fluent::lint::builtin_keyword_idents)
1989                 .set_arg("kw", ident.clone())
1990                 .set_arg("next", next_edition)
1991                 .span_suggestion(
1992                     ident.span,
1993                     fluent::lint::suggestion,
1994                     format!("r#{}", ident),
1995                     Applicability::MachineApplicable,
1996                 )
1997                 .emit();
1998         });
1999     }
2000 }
2001
2002 impl EarlyLintPass for KeywordIdents {
2003     fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
2004         self.check_tokens(cx, mac_def.body.inner_tokens());
2005     }
2006     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
2007         self.check_tokens(cx, mac.args.inner_tokens());
2008     }
2009     fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
2010         self.check_ident_token(cx, UnderMacro(false), ident);
2011     }
2012 }
2013
2014 declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
2015
2016 impl ExplicitOutlivesRequirements {
2017     fn lifetimes_outliving_lifetime<'tcx>(
2018         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2019         def_id: DefId,
2020     ) -> Vec<ty::Region<'tcx>> {
2021         inferred_outlives
2022             .iter()
2023             .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2024                 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
2025                     ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
2026                     _ => None,
2027                 },
2028                 _ => None,
2029             })
2030             .collect()
2031     }
2032
2033     fn lifetimes_outliving_type<'tcx>(
2034         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2035         index: u32,
2036     ) -> Vec<ty::Region<'tcx>> {
2037         inferred_outlives
2038             .iter()
2039             .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2040                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
2041                     a.is_param(index).then_some(b)
2042                 }
2043                 _ => None,
2044             })
2045             .collect()
2046     }
2047
2048     fn collect_outlives_bound_spans<'tcx>(
2049         &self,
2050         tcx: TyCtxt<'tcx>,
2051         bounds: &hir::GenericBounds<'_>,
2052         inferred_outlives: &[ty::Region<'tcx>],
2053     ) -> Vec<(usize, Span)> {
2054         use rustc_middle::middle::resolve_lifetime::Region;
2055
2056         bounds
2057             .iter()
2058             .enumerate()
2059             .filter_map(|(i, bound)| {
2060                 if let hir::GenericBound::Outlives(lifetime) = bound {
2061                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
2062                         Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
2063                             if let ty::ReEarlyBound(ebr) = **r {
2064                                 ebr.def_id == def_id
2065                             } else {
2066                                 false
2067                             }
2068                         }),
2069                         _ => false,
2070                     };
2071                     is_inferred.then_some((i, bound.span()))
2072                 } else {
2073                     None
2074                 }
2075             })
2076             .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
2077             .collect()
2078     }
2079
2080     fn consolidate_outlives_bound_spans(
2081         &self,
2082         lo: Span,
2083         bounds: &hir::GenericBounds<'_>,
2084         bound_spans: Vec<(usize, Span)>,
2085     ) -> Vec<Span> {
2086         if bounds.is_empty() {
2087             return Vec::new();
2088         }
2089         if bound_spans.len() == bounds.len() {
2090             let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
2091             // If all bounds are inferable, we want to delete the colon, so
2092             // start from just after the parameter (span passed as argument)
2093             vec![lo.to(last_bound_span)]
2094         } else {
2095             let mut merged = Vec::new();
2096             let mut last_merged_i = None;
2097
2098             let mut from_start = true;
2099             for (i, bound_span) in bound_spans {
2100                 match last_merged_i {
2101                     // If the first bound is inferable, our span should also eat the leading `+`.
2102                     None if i == 0 => {
2103                         merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2104                         last_merged_i = Some(0);
2105                     }
2106                     // If consecutive bounds are inferable, merge their spans
2107                     Some(h) if i == h + 1 => {
2108                         if let Some(tail) = merged.last_mut() {
2109                             // Also eat the trailing `+` if the first
2110                             // more-than-one bound is inferable
2111                             let to_span = if from_start && i < bounds.len() {
2112                                 bounds[i + 1].span().shrink_to_lo()
2113                             } else {
2114                                 bound_span
2115                             };
2116                             *tail = tail.to(to_span);
2117                             last_merged_i = Some(i);
2118                         } else {
2119                             bug!("another bound-span visited earlier");
2120                         }
2121                     }
2122                     _ => {
2123                         // When we find a non-inferable bound, subsequent inferable bounds
2124                         // won't be consecutive from the start (and we'll eat the leading
2125                         // `+` rather than the trailing one)
2126                         from_start = false;
2127                         merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
2128                         last_merged_i = Some(i);
2129                     }
2130                 }
2131             }
2132             merged
2133         }
2134     }
2135 }
2136
2137 impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2138     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
2139         use rustc_middle::middle::resolve_lifetime::Region;
2140
2141         let def_id = item.def_id.def_id;
2142         if let hir::ItemKind::Struct(_, ref hir_generics)
2143         | hir::ItemKind::Enum(_, ref hir_generics)
2144         | hir::ItemKind::Union(_, ref hir_generics) = item.kind
2145         {
2146             let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2147             if inferred_outlives.is_empty() {
2148                 return;
2149             }
2150
2151             let ty_generics = cx.tcx.generics_of(def_id);
2152
2153             let mut bound_count = 0;
2154             let mut lint_spans = Vec::new();
2155             let mut where_lint_spans = Vec::new();
2156             let mut dropped_predicate_count = 0;
2157             let num_predicates = hir_generics.predicates.len();
2158             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
2159                 let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
2160                     hir::WherePredicate::RegionPredicate(predicate) => {
2161                         if let Some(Region::EarlyBound(region_def_id)) =
2162                             cx.tcx.named_region(predicate.lifetime.hir_id)
2163                         {
2164                             (
2165                                 Self::lifetimes_outliving_lifetime(
2166                                     inferred_outlives,
2167                                     region_def_id,
2168                                 ),
2169                                 &predicate.bounds,
2170                                 predicate.span,
2171                                 predicate.in_where_clause,
2172                             )
2173                         } else {
2174                             continue;
2175                         }
2176                     }
2177                     hir::WherePredicate::BoundPredicate(predicate) => {
2178                         // FIXME we can also infer bounds on associated types,
2179                         // and should check for them here.
2180                         match predicate.bounded_ty.kind {
2181                             hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2182                                 let Res::Def(DefKind::TyParam, def_id) = path.res else {
2183                                     continue
2184                                 };
2185                                 let index = ty_generics.param_def_id_to_index[&def_id];
2186                                 (
2187                                     Self::lifetimes_outliving_type(inferred_outlives, index),
2188                                     &predicate.bounds,
2189                                     predicate.span,
2190                                     predicate.origin == PredicateOrigin::WhereClause,
2191                                 )
2192                             }
2193                             _ => {
2194                                 continue;
2195                             }
2196                         }
2197                     }
2198                     _ => continue,
2199                 };
2200                 if relevant_lifetimes.is_empty() {
2201                     continue;
2202                 }
2203
2204                 let bound_spans =
2205                     self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
2206                 bound_count += bound_spans.len();
2207
2208                 let drop_predicate = bound_spans.len() == bounds.len();
2209                 if drop_predicate {
2210                     dropped_predicate_count += 1;
2211                 }
2212
2213                 if drop_predicate && !in_where_clause {
2214                     lint_spans.push(span);
2215                 } else if drop_predicate && i + 1 < num_predicates {
2216                     // If all the bounds on a predicate were inferable and there are
2217                     // further predicates, we want to eat the trailing comma.
2218                     let next_predicate_span = hir_generics.predicates[i + 1].span();
2219                     where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
2220                 } else {
2221                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
2222                         span.shrink_to_lo(),
2223                         bounds,
2224                         bound_spans,
2225                     ));
2226                 }
2227             }
2228
2229             // If all predicates are inferable, drop the entire clause
2230             // (including the `where`)
2231             if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
2232             {
2233                 let where_span = hir_generics.where_clause_span;
2234                 // Extend the where clause back to the closing `>` of the
2235                 // generics, except for tuple struct, which have the `where`
2236                 // after the fields of the struct.
2237                 let full_where_span =
2238                     if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
2239                         where_span
2240                     } else {
2241                         hir_generics.span.shrink_to_hi().to(where_span)
2242                     };
2243                 lint_spans.push(full_where_span);
2244             } else {
2245                 lint_spans.extend(where_lint_spans);
2246             }
2247
2248             if !lint_spans.is_empty() {
2249                 cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
2250                     lint.build(fluent::lint::builtin_explicit_outlives)
2251                         .set_arg("count", bound_count)
2252                         .multipart_suggestion(
2253                             fluent::lint::suggestion,
2254                             lint_spans
2255                                 .into_iter()
2256                                 .map(|span| (span, String::new()))
2257                                 .collect::<Vec<_>>(),
2258                             Applicability::MachineApplicable,
2259                         )
2260                         .emit();
2261                 });
2262             }
2263         }
2264     }
2265 }
2266
2267 declare_lint! {
2268     /// The `incomplete_features` lint detects unstable features enabled with
2269     /// the [`feature` attribute] that may function improperly in some or all
2270     /// cases.
2271     ///
2272     /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2273     ///
2274     /// ### Example
2275     ///
2276     /// ```rust
2277     /// #![feature(generic_const_exprs)]
2278     /// ```
2279     ///
2280     /// {{produces}}
2281     ///
2282     /// ### Explanation
2283     ///
2284     /// Although it is encouraged for people to experiment with unstable
2285     /// features, some of them are known to be incomplete or faulty. This lint
2286     /// is a signal that the feature has not yet been finished, and you may
2287     /// experience problems with it.
2288     pub INCOMPLETE_FEATURES,
2289     Warn,
2290     "incomplete features that may function improperly in some or all cases"
2291 }
2292
2293 declare_lint_pass!(
2294     /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
2295     IncompleteFeatures => [INCOMPLETE_FEATURES]
2296 );
2297
2298 impl EarlyLintPass for IncompleteFeatures {
2299     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
2300         let features = cx.sess().features_untracked();
2301         features
2302             .declared_lang_features
2303             .iter()
2304             .map(|(name, span, _)| (name, span))
2305             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
2306             .filter(|(&name, _)| features.incomplete(name))
2307             .for_each(|(&name, &span)| {
2308                 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
2309                     let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
2310                     builder.set_arg("name", name);
2311                     if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
2312                         builder.set_arg("n", n);
2313                         builder.note(fluent::lint::note);
2314                     }
2315                     if HAS_MIN_FEATURES.contains(&name) {
2316                         builder.help(fluent::lint::help);
2317                     }
2318                     builder.emit();
2319                 })
2320             });
2321     }
2322 }
2323
2324 const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
2325
2326 declare_lint! {
2327     /// The `invalid_value` lint detects creating a value that is not valid,
2328     /// such as a null reference.
2329     ///
2330     /// ### Example
2331     ///
2332     /// ```rust,no_run
2333     /// # #![allow(unused)]
2334     /// unsafe {
2335     ///     let x: &'static i32 = std::mem::zeroed();
2336     /// }
2337     /// ```
2338     ///
2339     /// {{produces}}
2340     ///
2341     /// ### Explanation
2342     ///
2343     /// In some situations the compiler can detect that the code is creating
2344     /// an invalid value, which should be avoided.
2345     ///
2346     /// In particular, this lint will check for improper use of
2347     /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2348     /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2349     /// lint should provide extra information to indicate what the problem is
2350     /// and a possible solution.
2351     ///
2352     /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2353     /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2354     /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2355     /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2356     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2357     pub INVALID_VALUE,
2358     Warn,
2359     "an invalid value is being created (such as a null reference)"
2360 }
2361
2362 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2363
2364 impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2365     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2366         #[derive(Debug, Copy, Clone, PartialEq)]
2367         enum InitKind {
2368             Zeroed,
2369             Uninit,
2370         }
2371
2372         /// Information about why a type cannot be initialized this way.
2373         /// Contains an error message and optionally a span to point at.
2374         type InitError = (String, Option<Span>);
2375
2376         /// Test if this constant is all-0.
2377         fn is_zero(expr: &hir::Expr<'_>) -> bool {
2378             use hir::ExprKind::*;
2379             use rustc_ast::LitKind::*;
2380             match &expr.kind {
2381                 Lit(lit) => {
2382                     if let Int(i, _) = lit.node {
2383                         i == 0
2384                     } else {
2385                         false
2386                     }
2387                 }
2388                 Tup(tup) => tup.iter().all(is_zero),
2389                 _ => false,
2390             }
2391         }
2392
2393         /// Determine if this expression is a "dangerous initialization".
2394         fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
2395             if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
2396                 // Find calls to `mem::{uninitialized,zeroed}` methods.
2397                 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2398                     let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2399                     match cx.tcx.get_diagnostic_name(def_id) {
2400                         Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2401                         Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2402                         Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2403                         _ => {}
2404                     }
2405                 }
2406             } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
2407                 // Find problematic calls to `MaybeUninit::assume_init`.
2408                 let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
2409                 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2410                     // This is a call to *some* method named `assume_init`.
2411                     // See if the `self` parameter is one of the dangerous constructors.
2412                     if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
2413                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2414                             let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2415                             match cx.tcx.get_diagnostic_name(def_id) {
2416                                 Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2417                                 Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2418                                 _ => {}
2419                             }
2420                         }
2421                     }
2422                 }
2423             }
2424
2425             None
2426         }
2427
2428         /// Test if this enum has several actually "existing" variants.
2429         /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
2430         fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
2431             // As an approximation, we only count dataless variants. Those are definitely inhabited.
2432             let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
2433             existing_variants > 1
2434         }
2435
2436         /// Return `Some` only if we are sure this type does *not*
2437         /// allow zero initialization.
2438         fn ty_find_init_error<'tcx>(
2439             cx: &LateContext<'tcx>,
2440             ty: Ty<'tcx>,
2441             init: InitKind,
2442         ) -> Option<InitError> {
2443             use rustc_type_ir::sty::TyKind::*;
2444             match ty.kind() {
2445                 // Primitive types that don't like 0 as a value.
2446                 Ref(..) => Some(("references must be non-null".to_string(), None)),
2447                 Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)),
2448                 FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)),
2449                 Never => Some(("the `!` type has no valid value".to_string(), None)),
2450                 RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) =>
2451                 // raw ptr to dyn Trait
2452                 {
2453                     Some(("the vtable of a wide raw pointer must be non-null".to_string(), None))
2454                 }
2455                 // Primitive types with other constraints.
2456                 Bool if init == InitKind::Uninit => {
2457                     Some(("booleans must be either `true` or `false`".to_string(), None))
2458                 }
2459                 Char if init == InitKind::Uninit => {
2460                     Some(("characters must be a valid Unicode codepoint".to_string(), None))
2461                 }
2462                 Int(_) | Uint(_) if init == InitKind::Uninit => {
2463                     Some(("integers must not be uninitialized".to_string(), None))
2464                 }
2465                 Float(_) if init == InitKind::Uninit => {
2466                     Some(("floats must not be uninitialized".to_string(), None))
2467                 }
2468                 RawPtr(_) if init == InitKind::Uninit => {
2469                     Some(("raw pointers must not be uninitialized".to_string(), None))
2470                 }
2471                 // Recurse and checks for some compound types.
2472                 Adt(adt_def, substs) if !adt_def.is_union() => {
2473                     // First check if this ADT has a layout attribute (like `NonNull` and friends).
2474                     use std::ops::Bound;
2475                     match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
2476                         // We exploit here that `layout_scalar_valid_range` will never
2477                         // return `Bound::Excluded`.  (And we have tests checking that we
2478                         // handle the attribute correctly.)
2479                         (Bound::Included(lo), _) if lo > 0 => {
2480                             return Some((format!("`{}` must be non-null", ty), None));
2481                         }
2482                         (Bound::Included(_), _) | (_, Bound::Included(_))
2483                             if init == InitKind::Uninit =>
2484                         {
2485                             return Some((
2486                                 format!(
2487                                     "`{}` must be initialized inside its custom valid range",
2488                                     ty,
2489                                 ),
2490                                 None,
2491                             ));
2492                         }
2493                         _ => {}
2494                     }
2495                     // Now, recurse.
2496                     match adt_def.variants().len() {
2497                         0 => Some(("enums with no variants have no valid value".to_string(), None)),
2498                         1 => {
2499                             // Struct, or enum with exactly one variant.
2500                             // Proceed recursively, check all fields.
2501                             let variant = &adt_def.variant(VariantIdx::from_u32(0));
2502                             variant.fields.iter().find_map(|field| {
2503                                 ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
2504                                     |(mut msg, span)| {
2505                                         if span.is_none() {
2506                                             // Point to this field, should be helpful for figuring
2507                                             // out where the source of the error is.
2508                                             let span = cx.tcx.def_span(field.did);
2509                                             write!(
2510                                                 &mut msg,
2511                                                 " (in this {} field)",
2512                                                 adt_def.descr()
2513                                             )
2514                                             .unwrap();
2515                                             (msg, Some(span))
2516                                         } else {
2517                                             // Just forward.
2518                                             (msg, span)
2519                                         }
2520                                     },
2521                                 )
2522                             })
2523                         }
2524                         // Multi-variant enum.
2525                         _ => {
2526                             if init == InitKind::Uninit && is_multi_variant(*adt_def) {
2527                                 let span = cx.tcx.def_span(adt_def.did());
2528                                 Some((
2529                                     "enums have to be initialized to a variant".to_string(),
2530                                     Some(span),
2531                                 ))
2532                             } else {
2533                                 // In principle, for zero-initialization we could figure out which variant corresponds
2534                                 // to tag 0, and check that... but for now we just accept all zero-initializations.
2535                                 None
2536                             }
2537                         }
2538                     }
2539                 }
2540                 Tuple(..) => {
2541                     // Proceed recursively, check all fields.
2542                     ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2543                 }
2544                 Array(ty, len) => {
2545                     if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
2546                         // Array length known at array non-empty -- recurse.
2547                         ty_find_init_error(cx, *ty, init)
2548                     } else {
2549                         // Empty array or size unknown.
2550                         None
2551                     }
2552                 }
2553                 // Conservative fallback.
2554                 _ => None,
2555             }
2556         }
2557
2558         if let Some(init) = is_dangerous_init(cx, expr) {
2559             // This conjures an instance of a type out of nothing,
2560             // using zeroed or uninitialized memory.
2561             // We are extremely conservative with what we warn about.
2562             let conjured_ty = cx.typeck_results().expr_ty(expr);
2563             if let Some((msg, span)) =
2564                 with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
2565             {
2566                 // FIXME(davidtwco): make translatable
2567                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
2568                     let mut err = lint.build(&format!(
2569                         "the type `{}` does not permit {}",
2570                         conjured_ty,
2571                         match init {
2572                             InitKind::Zeroed => "zero-initialization",
2573                             InitKind::Uninit => "being left uninitialized",
2574                         },
2575                     ));
2576                     err.span_label(expr.span, "this code causes undefined behavior when executed");
2577                     err.span_label(
2578                         expr.span,
2579                         "help: use `MaybeUninit<T>` instead, \
2580                             and only call `assume_init` after initialization is done",
2581                     );
2582                     if let Some(span) = span {
2583                         err.span_note(span, &msg);
2584                     } else {
2585                         err.note(&msg);
2586                     }
2587                     err.emit();
2588                 });
2589             }
2590         }
2591     }
2592 }
2593
2594 declare_lint! {
2595     /// The `clashing_extern_declarations` lint detects when an `extern fn`
2596     /// has been declared with the same name but different types.
2597     ///
2598     /// ### Example
2599     ///
2600     /// ```rust
2601     /// mod m {
2602     ///     extern "C" {
2603     ///         fn foo();
2604     ///     }
2605     /// }
2606     ///
2607     /// extern "C" {
2608     ///     fn foo(_: u32);
2609     /// }
2610     /// ```
2611     ///
2612     /// {{produces}}
2613     ///
2614     /// ### Explanation
2615     ///
2616     /// Because two symbols of the same name cannot be resolved to two
2617     /// different functions at link time, and one function cannot possibly
2618     /// have two types, a clashing extern declaration is almost certainly a
2619     /// mistake. Check to make sure that the `extern` definitions are correct
2620     /// and equivalent, and possibly consider unifying them in one location.
2621     ///
2622     /// This lint does not run between crates because a project may have
2623     /// dependencies which both rely on the same extern function, but declare
2624     /// it in a different (but valid) way. For example, they may both declare
2625     /// an opaque type for one or more of the arguments (which would end up
2626     /// distinct types), or use types that are valid conversions in the
2627     /// language the `extern fn` is defined in. In these cases, the compiler
2628     /// can't say that the clashing declaration is incorrect.
2629     pub CLASHING_EXTERN_DECLARATIONS,
2630     Warn,
2631     "detects when an extern fn has been declared with the same name but different types"
2632 }
2633
2634 pub struct ClashingExternDeclarations {
2635     /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
2636     /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
2637     /// the symbol should be reported as a clashing declaration.
2638     // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
2639     // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
2640     seen_decls: FxHashMap<Symbol, HirId>,
2641 }
2642
2643 /// Differentiate between whether the name for an extern decl came from the link_name attribute or
2644 /// just from declaration itself. This is important because we don't want to report clashes on
2645 /// symbol name if they don't actually clash because one or the other links against a symbol with a
2646 /// different name.
2647 enum SymbolName {
2648     /// The name of the symbol + the span of the annotation which introduced the link name.
2649     Link(Symbol, Span),
2650     /// No link name, so just the name of the symbol.
2651     Normal(Symbol),
2652 }
2653
2654 impl SymbolName {
2655     fn get_name(&self) -> Symbol {
2656         match self {
2657             SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
2658         }
2659     }
2660 }
2661
2662 impl ClashingExternDeclarations {
2663     pub(crate) fn new() -> Self {
2664         ClashingExternDeclarations { seen_decls: FxHashMap::default() }
2665     }
2666     /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
2667     /// for the item, return its HirId without updating the set.
2668     fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
2669         let did = fi.def_id.to_def_id();
2670         let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
2671         let name = Symbol::intern(tcx.symbol_name(instance).name);
2672         if let Some(&hir_id) = self.seen_decls.get(&name) {
2673             // Avoid updating the map with the new entry when we do find a collision. We want to
2674             // make sure we're always pointing to the first definition as the previous declaration.
2675             // This lets us avoid emitting "knock-on" diagnostics.
2676             Some(hir_id)
2677         } else {
2678             self.seen_decls.insert(name, fi.hir_id())
2679         }
2680     }
2681
2682     /// Get the name of the symbol that's linked against for a given extern declaration. That is,
2683     /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
2684     /// symbol's name.
2685     fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
2686         if let Some((overridden_link_name, overridden_link_name_span)) =
2687             tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
2688                 // FIXME: Instead of searching through the attributes again to get span
2689                 // information, we could have codegen_fn_attrs also give span information back for
2690                 // where the attribute was defined. However, until this is found to be a
2691                 // bottleneck, this does just fine.
2692                 (
2693                     overridden_link_name,
2694                     tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
2695                 )
2696             })
2697         {
2698             SymbolName::Link(overridden_link_name, overridden_link_name_span)
2699         } else {
2700             SymbolName::Normal(fi.ident.name)
2701         }
2702     }
2703
2704     /// Checks whether two types are structurally the same enough that the declarations shouldn't
2705     /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
2706     /// with the same members (as the declarations shouldn't clash).
2707     fn structurally_same_type<'tcx>(
2708         cx: &LateContext<'tcx>,
2709         a: Ty<'tcx>,
2710         b: Ty<'tcx>,
2711         ckind: CItemKind,
2712     ) -> bool {
2713         fn structurally_same_type_impl<'tcx>(
2714             seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
2715             cx: &LateContext<'tcx>,
2716             a: Ty<'tcx>,
2717             b: Ty<'tcx>,
2718             ckind: CItemKind,
2719         ) -> bool {
2720             debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2721             let tcx = cx.tcx;
2722
2723             // Given a transparent newtype, reach through and grab the inner
2724             // type unless the newtype makes the type non-null.
2725             let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
2726                 let mut ty = ty;
2727                 loop {
2728                     if let ty::Adt(def, substs) = *ty.kind() {
2729                         let is_transparent = def.repr().transparent();
2730                         let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
2731                         debug!(
2732                             "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
2733                             ty, is_transparent, is_non_null
2734                         );
2735                         if is_transparent && !is_non_null {
2736                             debug_assert!(def.variants().len() == 1);
2737                             let v = &def.variant(VariantIdx::new(0));
2738                             ty = transparent_newtype_field(tcx, v)
2739                                 .expect(
2740                                     "single-variant transparent structure with zero-sized field",
2741                                 )
2742                                 .ty(tcx, substs);
2743                             continue;
2744                         }
2745                     }
2746                     debug!("non_transparent_ty -> {:?}", ty);
2747                     return ty;
2748                 }
2749             };
2750
2751             let a = non_transparent_ty(a);
2752             let b = non_transparent_ty(b);
2753
2754             if !seen_types.insert((a, b)) {
2755                 // We've encountered a cycle. There's no point going any further -- the types are
2756                 // structurally the same.
2757                 return true;
2758             }
2759             let tcx = cx.tcx;
2760             if a == b {
2761                 // All nominally-same types are structurally same, too.
2762                 true
2763             } else {
2764                 // Do a full, depth-first comparison between the two.
2765                 use rustc_type_ir::sty::TyKind::*;
2766                 let a_kind = a.kind();
2767                 let b_kind = b.kind();
2768
2769                 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
2770                     debug!("compare_layouts({:?}, {:?})", a, b);
2771                     let a_layout = &cx.layout_of(a)?.layout.abi();
2772                     let b_layout = &cx.layout_of(b)?.layout.abi();
2773                     debug!(
2774                         "comparing layouts: {:?} == {:?} = {}",
2775                         a_layout,
2776                         b_layout,
2777                         a_layout == b_layout
2778                     );
2779                     Ok(a_layout == b_layout)
2780                 };
2781
2782                 #[allow(rustc::usage_of_ty_tykind)]
2783                 let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
2784                     kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
2785                 };
2786
2787                 ensure_sufficient_stack(|| {
2788                     match (a_kind, b_kind) {
2789                         (Adt(a_def, _), Adt(b_def, _)) => {
2790                             // We can immediately rule out these types as structurally same if
2791                             // their layouts differ.
2792                             match compare_layouts(a, b) {
2793                                 Ok(false) => return false,
2794                                 _ => (), // otherwise, continue onto the full, fields comparison
2795                             }
2796
2797                             // Grab a flattened representation of all fields.
2798                             let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
2799                             let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
2800
2801                             // Perform a structural comparison for each field.
2802                             a_fields.eq_by(
2803                                 b_fields,
2804                                 |&ty::FieldDef { did: a_did, .. },
2805                                  &ty::FieldDef { did: b_did, .. }| {
2806                                     structurally_same_type_impl(
2807                                         seen_types,
2808                                         cx,
2809                                         tcx.type_of(a_did),
2810                                         tcx.type_of(b_did),
2811                                         ckind,
2812                                     )
2813                                 },
2814                             )
2815                         }
2816                         (Array(a_ty, a_const), Array(b_ty, b_const)) => {
2817                             // For arrays, we also check the constness of the type.
2818                             a_const.kind() == b_const.kind()
2819                                 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2820                         }
2821                         (Slice(a_ty), Slice(b_ty)) => {
2822                             structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2823                         }
2824                         (RawPtr(a_tymut), RawPtr(b_tymut)) => {
2825                             a_tymut.mutbl == b_tymut.mutbl
2826                                 && structurally_same_type_impl(
2827                                     seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
2828                                 )
2829                         }
2830                         (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
2831                             // For structural sameness, we don't need the region to be same.
2832                             a_mut == b_mut
2833                                 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2834                         }
2835                         (FnDef(..), FnDef(..)) => {
2836                             let a_poly_sig = a.fn_sig(tcx);
2837                             let b_poly_sig = b.fn_sig(tcx);
2838
2839                             // We don't compare regions, but leaving bound regions around ICEs, so
2840                             // we erase them.
2841                             let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
2842                             let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
2843
2844                             (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
2845                                 == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
2846                                 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2847                                     structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
2848                                 })
2849                                 && structurally_same_type_impl(
2850                                     seen_types,
2851                                     cx,
2852                                     a_sig.output(),
2853                                     b_sig.output(),
2854                                     ckind,
2855                                 )
2856                         }
2857                         (Tuple(a_substs), Tuple(b_substs)) => {
2858                             a_substs.iter().eq_by(b_substs.iter(), |a_ty, b_ty| {
2859                                 structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2860                             })
2861                         }
2862                         // For these, it's not quite as easy to define structural-sameness quite so easily.
2863                         // For the purposes of this lint, take the conservative approach and mark them as
2864                         // not structurally same.
2865                         (Dynamic(..), Dynamic(..))
2866                         | (Error(..), Error(..))
2867                         | (Closure(..), Closure(..))
2868                         | (Generator(..), Generator(..))
2869                         | (GeneratorWitness(..), GeneratorWitness(..))
2870                         | (Projection(..), Projection(..))
2871                         | (Opaque(..), Opaque(..)) => false,
2872
2873                         // These definitely should have been caught above.
2874                         (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
2875
2876                         // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
2877                         // enum layout optimisation is being applied.
2878                         (Adt(..), other_kind) | (other_kind, Adt(..))
2879                             if is_primitive_or_pointer(other_kind) =>
2880                         {
2881                             let (primitive, adt) =
2882                                 if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
2883                             if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2884                                 ty == primitive
2885                             } else {
2886                                 compare_layouts(a, b).unwrap_or(false)
2887                             }
2888                         }
2889                         // Otherwise, just compare the layouts. This may fail to lint for some
2890                         // incompatible types, but at the very least, will stop reads into
2891                         // uninitialised memory.
2892                         _ => compare_layouts(a, b).unwrap_or(false),
2893                     }
2894                 })
2895             }
2896         }
2897         let mut seen_types = FxHashSet::default();
2898         structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
2899     }
2900 }
2901
2902 impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
2903
2904 impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
2905     fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
2906         trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
2907         if let ForeignItemKind::Fn(..) = this_fi.kind {
2908             let tcx = cx.tcx;
2909             if let Some(existing_hid) = self.insert(tcx, this_fi) {
2910                 let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
2911                 let this_decl_ty = tcx.type_of(this_fi.def_id);
2912                 debug!(
2913                     "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
2914                     existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
2915                 );
2916                 // Check that the declarations match.
2917                 if !Self::structurally_same_type(
2918                     cx,
2919                     existing_decl_ty,
2920                     this_decl_ty,
2921                     CItemKind::Declaration,
2922                 ) {
2923                     let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
2924                     let orig = Self::name_of_extern_decl(tcx, orig_fi);
2925
2926                     // We want to ensure that we use spans for both decls that include where the
2927                     // name was defined, whether that was from the link_name attribute or not.
2928                     let get_relevant_span =
2929                         |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
2930                             SymbolName::Normal(_) => fi.span,
2931                             SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
2932                         };
2933                     // Finally, emit the diagnostic.
2934                     tcx.struct_span_lint_hir(
2935                         CLASHING_EXTERN_DECLARATIONS,
2936                         this_fi.hir_id(),
2937                         get_relevant_span(this_fi),
2938                         |lint| {
2939                             let mut expected_str = DiagnosticStyledString::new();
2940                             expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
2941                             let mut found_str = DiagnosticStyledString::new();
2942                             found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
2943
2944                             lint.build(if orig.get_name() == this_fi.ident.name {
2945                                 fluent::lint::builtin_clashing_extern_same_name
2946                             } else {
2947                                 fluent::lint::builtin_clashing_extern_diff_name
2948                             })
2949                             .set_arg("this_fi", this_fi.ident.name)
2950                             .set_arg("orig", orig.get_name())
2951                             .span_label(
2952                                 get_relevant_span(orig_fi),
2953                                 fluent::lint::previous_decl_label,
2954                             )
2955                             .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
2956                             // FIXME(davidtwco): translatable expected/found
2957                             .note_expected_found(&"", expected_str, &"", found_str)
2958                             .emit();
2959                         },
2960                     );
2961                 }
2962             }
2963         }
2964     }
2965 }
2966
2967 declare_lint! {
2968     /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2969     /// which causes [undefined behavior].
2970     ///
2971     /// ### Example
2972     ///
2973     /// ```rust,no_run
2974     /// # #![allow(unused)]
2975     /// use std::ptr;
2976     /// unsafe {
2977     ///     let x = &*ptr::null::<i32>();
2978     ///     let x = ptr::addr_of!(*ptr::null::<i32>());
2979     ///     let x = *(0 as *const i32);
2980     /// }
2981     /// ```
2982     ///
2983     /// {{produces}}
2984     ///
2985     /// ### Explanation
2986     ///
2987     /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
2988     /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
2989     ///
2990     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2991     pub DEREF_NULLPTR,
2992     Warn,
2993     "detects when an null pointer is dereferenced"
2994 }
2995
2996 declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
2997
2998 impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
2999     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
3000         /// test if expression is a null ptr
3001         fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
3002             match &expr.kind {
3003                 rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
3004                     if let rustc_hir::TyKind::Ptr(_) = ty.kind {
3005                         return is_zero(expr) || is_null_ptr(cx, expr);
3006                     }
3007                 }
3008                 // check for call to `core::ptr::null` or `core::ptr::null_mut`
3009                 rustc_hir::ExprKind::Call(ref path, _) => {
3010                     if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
3011                         if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
3012                             return matches!(
3013                                 cx.tcx.get_diagnostic_name(def_id),
3014                                 Some(sym::ptr_null | sym::ptr_null_mut)
3015                             );
3016                         }
3017                     }
3018                 }
3019                 _ => {}
3020             }
3021             false
3022         }
3023
3024         /// test if expression is the literal `0`
3025         fn is_zero(expr: &hir::Expr<'_>) -> bool {
3026             match &expr.kind {
3027                 rustc_hir::ExprKind::Lit(ref lit) => {
3028                     if let LitKind::Int(a, _) = lit.node {
3029                         return a == 0;
3030                     }
3031                 }
3032                 _ => {}
3033             }
3034             false
3035         }
3036
3037         if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
3038             if is_null_ptr(cx, expr_deref) {
3039                 cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
3040                     let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
3041                     err.span_label(expr.span, fluent::lint::label);
3042                     err.emit();
3043                 });
3044             }
3045         }
3046     }
3047 }
3048
3049 declare_lint! {
3050     /// The `named_asm_labels` lint detects the use of named labels in the
3051     /// inline `asm!` macro.
3052     ///
3053     /// ### Example
3054     ///
3055     /// ```rust,compile_fail
3056     /// use std::arch::asm;
3057     ///
3058     /// fn main() {
3059     ///     unsafe {
3060     ///         asm!("foo: bar");
3061     ///     }
3062     /// }
3063     /// ```
3064     ///
3065     /// {{produces}}
3066     ///
3067     /// ### Explanation
3068     ///
3069     /// LLVM is allowed to duplicate inline assembly blocks for any
3070     /// reason, for example when it is in a function that gets inlined. Because
3071     /// of this, GNU assembler [local labels] *must* be used instead of labels
3072     /// with a name. Using named labels might cause assembler or linker errors.
3073     ///
3074     /// See the explanation in [Rust By Example] for more details.
3075     ///
3076     /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
3077     /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
3078     pub NAMED_ASM_LABELS,
3079     Deny,
3080     "named labels in inline assembly",
3081 }
3082
3083 declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
3084
3085 impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
3086     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
3087         if let hir::Expr {
3088             kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
3089             ..
3090         } = expr
3091         {
3092             for (template_sym, template_snippet, template_span) in template_strs.iter() {
3093                 let template_str = template_sym.as_str();
3094                 let find_label_span = |needle: &str| -> Option<Span> {
3095                     if let Some(template_snippet) = template_snippet {
3096                         let snippet = template_snippet.as_str();
3097                         if let Some(pos) = snippet.find(needle) {
3098                             let end = pos
3099                                 + snippet[pos..]
3100                                     .find(|c| c == ':')
3101                                     .unwrap_or(snippet[pos..].len() - 1);
3102                             let inner = InnerSpan::new(pos, end);
3103                             return Some(template_span.from_inner(inner));
3104                         }
3105                     }
3106
3107                     None
3108                 };
3109
3110                 let mut found_labels = Vec::new();
3111
3112                 // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
3113                 let statements = template_str.split(|c| matches!(c, '\n' | ';'));
3114                 for statement in statements {
3115                     // If there's a comment, trim it from the statement
3116                     let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
3117                     let mut start_idx = 0;
3118                     for (idx, _) in statement.match_indices(':') {
3119                         let possible_label = statement[start_idx..idx].trim();
3120                         let mut chars = possible_label.chars();
3121                         let Some(c) = chars.next() else {
3122                             // Empty string means a leading ':' in this section, which is not a label
3123                             break
3124                         };
3125                         // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
3126                         if (c.is_alphabetic() || matches!(c, '.' | '_'))
3127                             && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
3128                         {
3129                             found_labels.push(possible_label);
3130                         } else {
3131                             // If we encounter a non-label, there cannot be any further labels, so stop checking
3132                             break;
3133                         }
3134
3135                         start_idx = idx + 1;
3136                     }
3137                 }
3138
3139                 debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
3140
3141                 if found_labels.len() > 0 {
3142                     let spans = found_labels
3143                         .into_iter()
3144                         .filter_map(|label| find_label_span(label))
3145                         .collect::<Vec<Span>>();
3146                     // If there were labels but we couldn't find a span, combine the warnings and use the template span
3147                     let target_spans: MultiSpan =
3148                         if spans.len() > 0 { spans.into() } else { (*template_span).into() };
3149
3150                     cx.lookup_with_diagnostics(
3151                             NAMED_ASM_LABELS,
3152                             Some(target_spans),
3153                             |diag| {
3154                                 diag.build(fluent::lint::builtin_asm_labels).emit();
3155                             },
3156                             BuiltinLintDiagnostics::NamedAsmLabel(
3157                                 "only local labels of the form `<number>:` should be used in inline asm"
3158                                     .to_string(),
3159                             ),
3160                         );
3161                 }
3162             }
3163         }
3164     }
3165 }
3166
3167 declare_lint! {
3168     /// The `special_module_name` lint detects module
3169     /// declarations for files that have a special meaning.
3170     ///
3171     /// ### Example
3172     ///
3173     /// ```rust,compile_fail
3174     /// mod lib;
3175     ///
3176     /// fn main() {
3177     ///     lib::run();
3178     /// }
3179     /// ```
3180     ///
3181     /// {{produces}}
3182     ///
3183     /// ### Explanation
3184     ///
3185     /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
3186     /// library or binary crate, so declaring them as modules
3187     /// will lead to miscompilation of the crate unless configured
3188     /// explicitly.
3189     ///
3190     /// To access a library from a binary target within the same crate,
3191     /// use `your_crate_name::` as the path path instead of `lib::`:
3192     ///
3193     /// ```rust,compile_fail
3194     /// // bar/src/lib.rs
3195     /// fn run() {
3196     ///     // ...
3197     /// }
3198     ///
3199     /// // bar/src/main.rs
3200     /// fn main() {
3201     ///     bar::run();
3202     /// }
3203     /// ```
3204     ///
3205     /// Binary targets cannot be used as libraries and so declaring
3206     /// one as a module is not allowed.
3207     pub SPECIAL_MODULE_NAME,
3208     Warn,
3209     "module declarations for files with a special meaning",
3210 }
3211
3212 declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
3213
3214 impl EarlyLintPass for SpecialModuleName {
3215     fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
3216         for item in &krate.items {
3217             if let ast::ItemKind::Mod(
3218                 _,
3219                 ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
3220             ) = item.kind
3221             {
3222                 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
3223                     continue;
3224                 }
3225
3226                 match item.ident.name.as_str() {
3227                     "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3228                         lint.build("found module declaration for lib.rs")
3229                             .note("lib.rs is the root of this crate's library target")
3230                             .help("to refer to it from other targets, use the library's name as the path")
3231                             .emit()
3232                     }),
3233                     "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3234                         lint.build("found module declaration for main.rs")
3235                             .note("a binary crate cannot be used as library")
3236                             .emit()
3237                     }),
3238                     _ => continue
3239                 }
3240             }
3241         }
3242     }
3243 }
3244
3245 pub use rustc_session::lint::builtin::UNEXPECTED_CFGS;
3246
3247 declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]);
3248
3249 impl EarlyLintPass for UnexpectedCfgs {
3250     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
3251         let cfg = &cx.sess().parse_sess.config;
3252         let check_cfg = &cx.sess().parse_sess.check_config;
3253         for &(name, value) in cfg {
3254             if let Some(names_valid) = &check_cfg.names_valid {
3255                 if !names_valid.contains(&name) {
3256                     cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
3257                         diag.build(fluent::lint::builtin_unexpected_cli_config_name)
3258                             .help(fluent::lint::help)
3259                             .set_arg("name", name)
3260                             .emit();
3261                     });
3262                 }
3263             }
3264             if let Some(value) = value {
3265                 if let Some(values) = &check_cfg.values_valid.get(&name) {
3266                     if !values.contains(&value) {
3267                         cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
3268                             diag.build(fluent::lint::builtin_unexpected_cli_config_value)
3269                                 .help(fluent::lint::help)
3270                                 .set_arg("name", name)
3271                                 .set_arg("value", value)
3272                                 .emit();
3273                         });
3274                     }
3275                 }
3276             }
3277         }
3278     }
3279 }