]> git.lizzy.rs Git - rust.git/blob - src/librustc_lint/builtin.rs
Rollup merge of #70561 - tshepang:obsolete-comment, r=petrochenkov
[rust.git] / src / librustc_lint / builtin.rs
1 //! Lints in the Rust compiler.
2 //!
3 //! This contains lints which can feasibly be implemented as their own
4 //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
5 //! definitions of lints that are emitted directly inside the main compiler.
6 //!
7 //! To add a new lint to rustc, declare it here using `declare_lint!()`.
8 //! Then add code to emit the new lint in the appropriate circumstances.
9 //! 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::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
24 use rustc_ast::ast::{self, Expr};
25 use rustc_ast::attr::{self, HasAttrs};
26 use rustc_ast::tokenstream::{TokenStream, TokenTree};
27 use rustc_ast::visit::{FnCtxt, FnKind};
28 use rustc_ast_pretty::pprust::{self, expr_to_string};
29 use rustc_data_structures::fx::FxHashSet;
30 use rustc_errors::{Applicability, DiagnosticBuilder};
31 use rustc_feature::Stability;
32 use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
33 use rustc_hir as hir;
34 use rustc_hir::def::{DefKind, Res};
35 use rustc_hir::def_id::DefId;
36 use rustc_hir::{GenericParamKind, PatKind};
37 use rustc_hir::{HirIdSet, Node};
38 use rustc_middle::lint::LintDiagnosticBuilder;
39 use rustc_middle::ty::{self, layout::VariantIdx, Ty, TyCtxt};
40 use rustc_session::lint::FutureIncompatibleInfo;
41 use rustc_span::edition::Edition;
42 use rustc_span::source_map::Spanned;
43 use rustc_span::symbol::{kw, sym, Symbol};
44 use rustc_span::{BytePos, Span};
45 use rustc_trait_selection::traits::misc::can_type_implement_copy;
46
47 use crate::nonstandard_style::{method_context, MethodLateContext};
48
49 use log::debug;
50 use std::fmt::Write;
51
52 // hardwired lints from librustc_middle
53 pub use rustc_session::lint::builtin::*;
54
55 declare_lint! {
56     WHILE_TRUE,
57     Warn,
58     "suggest using `loop { }` instead of `while true { }`"
59 }
60
61 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
62
63 /// Traverse through any amount of parenthesis and return the first non-parens expression.
64 fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
65     while let ast::ExprKind::Paren(sub) = &expr.kind {
66         expr = sub;
67     }
68     expr
69 }
70
71 impl EarlyLintPass for WhileTrue {
72     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
73         if let ast::ExprKind::While(cond, ..) = &e.kind {
74             if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
75                 if let ast::LitKind::Bool(true) = lit.kind {
76                     if !lit.span.from_expansion() {
77                         let msg = "denote infinite loops with `loop { ... }`";
78                         let condition_span = cx.sess.source_map().guess_head_span(e.span);
79                         cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
80                             lint.build(msg)
81                                 .span_suggestion_short(
82                                     condition_span,
83                                     "use `loop`",
84                                     "loop".to_owned(),
85                                     Applicability::MachineApplicable,
86                                 )
87                                 .emit();
88                         })
89                     }
90                 }
91             }
92         }
93     }
94 }
95
96 declare_lint! {
97     BOX_POINTERS,
98     Allow,
99     "use of owned (Box type) heap memory"
100 }
101
102 declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
103
104 impl BoxPointers {
105     fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
106         for leaf_ty in ty.walk() {
107             if leaf_ty.is_box() {
108                 cx.struct_span_lint(BOX_POINTERS, span, |lint| {
109                     lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
110                 });
111             }
112         }
113     }
114 }
115
116 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers {
117     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
118         match it.kind {
119             hir::ItemKind::Fn(..)
120             | hir::ItemKind::TyAlias(..)
121             | hir::ItemKind::Enum(..)
122             | hir::ItemKind::Struct(..)
123             | hir::ItemKind::Union(..) => {
124                 let def_id = cx.tcx.hir().local_def_id(it.hir_id);
125                 self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id))
126             }
127             _ => (),
128         }
129
130         // If it's a struct, we also have to check the fields' types
131         match it.kind {
132             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
133                 for struct_field in struct_def.fields() {
134                     let def_id = cx.tcx.hir().local_def_id(struct_field.hir_id);
135                     self.check_heap_type(cx, struct_field.span, cx.tcx.type_of(def_id));
136                 }
137             }
138             _ => (),
139         }
140     }
141
142     fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
143         let ty = cx.tables.node_type(e.hir_id);
144         self.check_heap_type(cx, e.span, ty);
145     }
146 }
147
148 declare_lint! {
149     NON_SHORTHAND_FIELD_PATTERNS,
150     Warn,
151     "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
152 }
153
154 declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
155
156 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
157     fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
158         if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
159             let variant = cx
160                 .tables
161                 .pat_ty(pat)
162                 .ty_adt_def()
163                 .expect("struct pattern type is not an ADT")
164                 .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id));
165             for fieldpat in field_pats {
166                 if fieldpat.is_shorthand {
167                     continue;
168                 }
169                 if fieldpat.span.from_expansion() {
170                     // Don't lint if this is a macro expansion: macro authors
171                     // shouldn't have to worry about this kind of style issue
172                     // (Issue #49588)
173                     continue;
174                 }
175                 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
176                     if cx.tcx.find_field_index(ident, &variant)
177                         == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables))
178                     {
179                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
180                             let mut err = lint
181                                 .build(&format!("the `{}:` in this pattern is redundant", ident));
182                             let binding = match binding_annot {
183                                 hir::BindingAnnotation::Unannotated => None,
184                                 hir::BindingAnnotation::Mutable => Some("mut"),
185                                 hir::BindingAnnotation::Ref => Some("ref"),
186                                 hir::BindingAnnotation::RefMut => Some("ref mut"),
187                             };
188                             let ident = if let Some(binding) = binding {
189                                 format!("{} {}", binding, ident)
190                             } else {
191                                 ident.to_string()
192                             };
193                             err.span_suggestion(
194                                 fieldpat.span,
195                                 "use shorthand field pattern",
196                                 ident,
197                                 Applicability::MachineApplicable,
198                             );
199                             err.emit();
200                         });
201                     }
202                 }
203             }
204         }
205     }
206 }
207
208 declare_lint! {
209     UNSAFE_CODE,
210     Allow,
211     "usage of `unsafe` code"
212 }
213
214 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
215
216 impl UnsafeCode {
217     fn report_unsafe(
218         &self,
219         cx: &EarlyContext<'_>,
220         span: Span,
221         decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
222     ) {
223         // This comes from a macro that has `#[allow_internal_unsafe]`.
224         if span.allows_unsafe() {
225             return;
226         }
227
228         cx.struct_span_lint(UNSAFE_CODE, span, decorate);
229     }
230 }
231
232 impl EarlyLintPass for UnsafeCode {
233     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
234         if attr.check_name(sym::allow_internal_unsafe) {
235             self.report_unsafe(cx, attr.span, |lint| {
236                 lint.build(
237                     "`allow_internal_unsafe` allows defining \
238                                                macros using unsafe without triggering \
239                                                the `unsafe_code` lint at their call site",
240                 )
241                 .emit()
242             });
243         }
244     }
245
246     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
247         if let ast::ExprKind::Block(ref blk, _) = e.kind {
248             // Don't warn about generated blocks; that'll just pollute the output.
249             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
250                 self.report_unsafe(cx, blk.span, |lint| {
251                     lint.build("usage of an `unsafe` block").emit()
252                 });
253             }
254         }
255     }
256
257     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
258         match it.kind {
259             ast::ItemKind::Trait(_, ast::Unsafe::Yes(_), ..) => {
260                 self.report_unsafe(cx, it.span, |lint| {
261                     lint.build("declaration of an `unsafe` trait").emit()
262                 })
263             }
264
265             ast::ItemKind::Impl { unsafety: ast::Unsafe::Yes(_), .. } => {
266                 self.report_unsafe(cx, it.span, |lint| {
267                     lint.build("implementation of an `unsafe` trait").emit()
268                 })
269             }
270
271             _ => {}
272         }
273     }
274
275     fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
276         if let FnKind::Fn(
277             ctxt,
278             _,
279             ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
280             _,
281             body,
282         ) = fk
283         {
284             let msg = match ctxt {
285                 FnCtxt::Foreign => return,
286                 FnCtxt::Free => "declaration of an `unsafe` function",
287                 FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
288                 FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
289             };
290             self.report_unsafe(cx, span, |lint| lint.build(msg).emit());
291         }
292     }
293 }
294
295 declare_lint! {
296     pub MISSING_DOCS,
297     Allow,
298     "detects missing documentation for public members",
299     report_in_external_macro
300 }
301
302 pub struct MissingDoc {
303     /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
304     doc_hidden_stack: Vec<bool>,
305
306     /// Private traits or trait items that leaked through. Don't check their methods.
307     private_traits: FxHashSet<hir::HirId>,
308 }
309
310 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
311
312 fn has_doc(attr: &ast::Attribute) -> bool {
313     if attr.is_doc_comment() {
314         return true;
315     }
316
317     if !attr.check_name(sym::doc) {
318         return false;
319     }
320
321     if attr.is_value_str() {
322         return true;
323     }
324
325     if let Some(list) = attr.meta_item_list() {
326         for meta in list {
327             if meta.check_name(sym::include) || meta.check_name(sym::hidden) {
328                 return true;
329             }
330         }
331     }
332
333     false
334 }
335
336 impl MissingDoc {
337     pub fn new() -> MissingDoc {
338         MissingDoc { doc_hidden_stack: vec![false], private_traits: FxHashSet::default() }
339     }
340
341     fn doc_hidden(&self) -> bool {
342         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
343     }
344
345     fn check_missing_docs_attrs(
346         &self,
347         cx: &LateContext<'_, '_>,
348         id: Option<hir::HirId>,
349         attrs: &[ast::Attribute],
350         sp: Span,
351         article: &'static str,
352         desc: &'static str,
353     ) {
354         // If we're building a test harness, then warning about
355         // documentation is probably not really relevant right now.
356         if cx.sess().opts.test {
357             return;
358         }
359
360         // `#[doc(hidden)]` disables missing_docs check.
361         if self.doc_hidden() {
362             return;
363         }
364
365         // Only check publicly-visible items, using the result from the privacy pass.
366         // It's an option so the crate root can also use this function (it doesn't
367         // have a `NodeId`).
368         if let Some(id) = id {
369             if !cx.access_levels.is_exported(id) {
370                 return;
371             }
372         }
373
374         let has_doc = attrs.iter().any(|a| has_doc(a));
375         if !has_doc {
376             cx.struct_span_lint(
377                 MISSING_DOCS,
378                 cx.tcx.sess.source_map().guess_head_span(sp),
379                 |lint| {
380                     lint.build(&format!("missing documentation for {} {}", article, desc)).emit()
381                 },
382             );
383         }
384     }
385 }
386
387 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
388     fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) {
389         let doc_hidden = self.doc_hidden()
390             || attrs.iter().any(|attr| {
391                 attr.check_name(sym::doc)
392                     && match attr.meta_item_list() {
393                         None => false,
394                         Some(l) => attr::list_contains_name(&l, sym::hidden),
395                     }
396             });
397         self.doc_hidden_stack.push(doc_hidden);
398     }
399
400     fn exit_lint_attrs(&mut self, _: &LateContext<'_, '_>, _attrs: &[ast::Attribute]) {
401         self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
402     }
403
404     fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) {
405         self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate");
406
407         for macro_def in krate.exported_macros {
408             let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
409             if !has_doc {
410                 cx.struct_span_lint(
411                     MISSING_DOCS,
412                     cx.tcx.sess.source_map().guess_head_span(macro_def.span),
413                     |lint| lint.build("missing documentation for macro").emit(),
414                 );
415             }
416         }
417     }
418
419     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
420         match it.kind {
421             hir::ItemKind::Trait(.., trait_item_refs) => {
422                 // Issue #11592: traits are always considered exported, even when private.
423                 if let hir::VisibilityKind::Inherited = it.vis.node {
424                     self.private_traits.insert(it.hir_id);
425                     for trait_item_ref in trait_item_refs {
426                         self.private_traits.insert(trait_item_ref.id.hir_id);
427                     }
428                     return;
429                 }
430             }
431             hir::ItemKind::Impl { of_trait: Some(ref trait_ref), items, .. } => {
432                 // If the trait is private, add the impl items to `private_traits` so they don't get
433                 // reported for missing docs.
434                 let real_trait = trait_ref.path.res.def_id();
435                 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
436                     if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
437                         if let hir::VisibilityKind::Inherited = item.vis.node {
438                             for impl_item_ref in items {
439                                 self.private_traits.insert(impl_item_ref.id.hir_id);
440                             }
441                         }
442                     }
443                 }
444                 return;
445             }
446
447             hir::ItemKind::TyAlias(..)
448             | hir::ItemKind::Fn(..)
449             | hir::ItemKind::Mod(..)
450             | hir::ItemKind::Enum(..)
451             | hir::ItemKind::Struct(..)
452             | hir::ItemKind::Union(..)
453             | hir::ItemKind::Const(..)
454             | hir::ItemKind::Static(..) => {}
455
456             _ => return,
457         };
458
459         let def_id = cx.tcx.hir().local_def_id(it.hir_id);
460         let (article, desc) = cx.tcx.article_and_description(def_id);
461
462         self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, article, desc);
463     }
464
465     fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) {
466         if self.private_traits.contains(&trait_item.hir_id) {
467             return;
468         }
469
470         let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id);
471         let (article, desc) = cx.tcx.article_and_description(def_id);
472
473         self.check_missing_docs_attrs(
474             cx,
475             Some(trait_item.hir_id),
476             &trait_item.attrs,
477             trait_item.span,
478             article,
479             desc,
480         );
481     }
482
483     fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplItem<'_>) {
484         // If the method is an impl for a trait, don't doc.
485         if method_context(cx, impl_item.hir_id) == MethodLateContext::TraitImpl {
486             return;
487         }
488
489         let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
490         let (article, desc) = cx.tcx.article_and_description(def_id);
491         self.check_missing_docs_attrs(
492             cx,
493             Some(impl_item.hir_id),
494             &impl_item.attrs,
495             impl_item.span,
496             article,
497             desc,
498         );
499     }
500
501     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField<'_>) {
502         if !sf.is_positional() {
503             self.check_missing_docs_attrs(
504                 cx,
505                 Some(sf.hir_id),
506                 &sf.attrs,
507                 sf.span,
508                 "a",
509                 "struct field",
510             )
511         }
512     }
513
514     fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant<'_>) {
515         self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a", "variant");
516     }
517 }
518
519 declare_lint! {
520     pub MISSING_COPY_IMPLEMENTATIONS,
521     Allow,
522     "detects potentially-forgotten implementations of `Copy`"
523 }
524
525 declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
526
527 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
528     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
529         if !cx.access_levels.is_reachable(item.hir_id) {
530             return;
531         }
532         let (def, ty) = match item.kind {
533             hir::ItemKind::Struct(_, ref ast_generics) => {
534                 if !ast_generics.params.is_empty() {
535                     return;
536                 }
537                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
538                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
539             }
540             hir::ItemKind::Union(_, ref ast_generics) => {
541                 if !ast_generics.params.is_empty() {
542                     return;
543                 }
544                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
545                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
546             }
547             hir::ItemKind::Enum(_, ref ast_generics) => {
548                 if !ast_generics.params.is_empty() {
549                     return;
550                 }
551                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
552                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
553             }
554             _ => return,
555         };
556         if def.has_dtor(cx.tcx) {
557             return;
558         }
559         let param_env = ty::ParamEnv::empty();
560         if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
561             return;
562         }
563         if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
564             cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
565                 lint.build(
566                     "type could implement `Copy`; consider adding `impl \
567                           Copy`",
568                 )
569                 .emit()
570             })
571         }
572     }
573 }
574
575 declare_lint! {
576     MISSING_DEBUG_IMPLEMENTATIONS,
577     Allow,
578     "detects missing implementations of Debug"
579 }
580
581 #[derive(Default)]
582 pub struct MissingDebugImplementations {
583     impling_types: Option<HirIdSet>,
584 }
585
586 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
587
588 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
589     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
590         if !cx.access_levels.is_reachable(item.hir_id) {
591             return;
592         }
593
594         match item.kind {
595             hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
596             _ => return,
597         }
598
599         let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) {
600             Some(debug) => debug,
601             None => return,
602         };
603
604         if self.impling_types.is_none() {
605             let mut impls = HirIdSet::default();
606             cx.tcx.for_each_impl(debug, |d| {
607                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
608                     if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(ty_def.did) {
609                         impls.insert(hir_id);
610                     }
611                 }
612             });
613
614             self.impling_types = Some(impls);
615             debug!("{:?}", self.impling_types);
616         }
617
618         if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
619             cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
620                 lint.build(&format!(
621                     "type does not implement `{}`; consider adding `#[derive(Debug)]` \
622                      or a manual implementation",
623                     cx.tcx.def_path_str(debug)
624                 ))
625                 .emit()
626             });
627         }
628     }
629 }
630
631 declare_lint! {
632     pub ANONYMOUS_PARAMETERS,
633     Allow,
634     "detects anonymous parameters",
635     @future_incompatible = FutureIncompatibleInfo {
636         reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
637         edition: Some(Edition::Edition2018),
638     };
639 }
640
641 declare_lint_pass!(
642     /// Checks for use of anonymous parameters (RFC 1685).
643     AnonymousParameters => [ANONYMOUS_PARAMETERS]
644 );
645
646 impl EarlyLintPass for AnonymousParameters {
647     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
648         if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind {
649             for arg in sig.decl.inputs.iter() {
650                 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
651                     if ident.name == kw::Invalid {
652                         cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
653                             let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
654
655                             let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
656                                 (snip.as_str(), Applicability::MachineApplicable)
657                             } else {
658                                 ("<type>", Applicability::HasPlaceholders)
659                             };
660
661                             lint.build(
662                                 "anonymous parameters are deprecated and will be \
663                                      removed in the next edition.",
664                             )
665                             .span_suggestion(
666                                 arg.pat.span,
667                                 "try naming the parameter or explicitly \
668                                             ignoring it",
669                                 format!("_: {}", ty_snip),
670                                 appl,
671                             )
672                             .emit();
673                         })
674                     }
675                 }
676             }
677         }
678     }
679 }
680
681 /// Check for use of attributes which have been deprecated.
682 #[derive(Clone)]
683 pub struct DeprecatedAttr {
684     // This is not free to compute, so we want to keep it around, rather than
685     // compute it for every attribute.
686     depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
687 }
688
689 impl_lint_pass!(DeprecatedAttr => []);
690
691 impl DeprecatedAttr {
692     pub fn new() -> DeprecatedAttr {
693         DeprecatedAttr { depr_attrs: deprecated_attributes() }
694     }
695 }
696
697 fn lint_deprecated_attr(
698     cx: &EarlyContext<'_>,
699     attr: &ast::Attribute,
700     msg: &str,
701     suggestion: Option<&str>,
702 ) {
703     cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
704         lint.build(msg)
705             .span_suggestion_short(
706                 attr.span,
707                 suggestion.unwrap_or("remove this attribute"),
708                 String::new(),
709                 Applicability::MachineApplicable,
710             )
711             .emit();
712     })
713 }
714
715 impl EarlyLintPass for DeprecatedAttr {
716     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
717         for &&(n, _, _, ref g) in &self.depr_attrs {
718             if attr.ident().map(|ident| ident.name) == Some(n) {
719                 if let &AttributeGate::Gated(
720                     Stability::Deprecated(link, suggestion),
721                     ref name,
722                     ref reason,
723                     _,
724                 ) = g
725                 {
726                     let msg =
727                         format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link);
728                     lint_deprecated_attr(cx, attr, &msg, suggestion);
729                 }
730                 return;
731             }
732         }
733         if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
734             let path_str = pprust::path_to_string(&attr.get_normal_item().path);
735             let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
736             lint_deprecated_attr(cx, attr, &msg, None);
737         }
738     }
739 }
740
741 fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
742     let mut attrs = attrs.iter().peekable();
743
744     // Accumulate a single span for sugared doc comments.
745     let mut sugared_span: Option<Span> = None;
746
747     while let Some(attr) = attrs.next() {
748         if attr.is_doc_comment() {
749             sugared_span =
750                 Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())));
751         }
752
753         if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() {
754             continue;
755         }
756
757         let span = sugared_span.take().unwrap_or_else(|| attr.span);
758
759         if attr.is_doc_comment() || attr.check_name(sym::doc) {
760             cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
761                 let mut err = lint.build("unused doc comment");
762                 err.span_label(
763                     node_span,
764                     format!("rustdoc does not generate documentation for {}", node_kind),
765                 );
766                 err.emit();
767             });
768         }
769     }
770 }
771
772 impl EarlyLintPass for UnusedDocComment {
773     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
774         let kind = match stmt.kind {
775             ast::StmtKind::Local(..) => "statements",
776             ast::StmtKind::Item(..) => "inner items",
777             // expressions will be reported by `check_expr`.
778             ast::StmtKind::Empty
779             | ast::StmtKind::Semi(_)
780             | ast::StmtKind::Expr(_)
781             | ast::StmtKind::MacCall(_) => return,
782         };
783
784         warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
785     }
786
787     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
788         let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
789         warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
790     }
791
792     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
793         warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
794     }
795 }
796
797 declare_lint! {
798     NO_MANGLE_CONST_ITEMS,
799     Deny,
800     "const items will not have their symbols exported"
801 }
802
803 declare_lint! {
804     NO_MANGLE_GENERIC_ITEMS,
805     Warn,
806     "generic items must be mangled"
807 }
808
809 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
810
811 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
812     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
813         match it.kind {
814             hir::ItemKind::Fn(.., ref generics, _) => {
815                 if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
816                     for param in generics.params {
817                         match param.kind {
818                             GenericParamKind::Lifetime { .. } => {}
819                             GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
820                                 cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, it.span, |lint| {
821                                     lint.build(
822                                         "functions generic over types or consts must be mangled",
823                                     )
824                                     .span_suggestion_short(
825                                         no_mangle_attr.span,
826                                         "remove this attribute",
827                                         String::new(),
828                                         // Use of `#[no_mangle]` suggests FFI intent; correct
829                                         // fix may be to monomorphize source by hand
830                                         Applicability::MaybeIncorrect,
831                                     )
832                                     .emit();
833                                 });
834                                 break;
835                             }
836                         }
837                     }
838                 }
839             }
840             hir::ItemKind::Const(..) => {
841                 if attr::contains_name(&it.attrs, sym::no_mangle) {
842                     // Const items do not refer to a particular location in memory, and therefore
843                     // don't have anything to attach a symbol to
844                     cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
845                         let msg = "const items should never be `#[no_mangle]`";
846                         let mut err = lint.build(msg);
847
848                         // account for "pub const" (#45562)
849                         let start = cx
850                             .tcx
851                             .sess
852                             .source_map()
853                             .span_to_snippet(it.span)
854                             .map(|snippet| snippet.find("const").unwrap_or(0))
855                             .unwrap_or(0) as u32;
856                         // `const` is 5 chars
857                         let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
858                         err.span_suggestion(
859                             const_span,
860                             "try a static value",
861                             "pub static".to_owned(),
862                             Applicability::MachineApplicable,
863                         );
864                         err.emit();
865                     });
866                 }
867             }
868             _ => {}
869         }
870     }
871 }
872
873 declare_lint! {
874     MUTABLE_TRANSMUTES,
875     Deny,
876     "mutating transmuted &mut T from &T may cause undefined behavior"
877 }
878
879 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
880
881 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
882     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
883         use rustc_target::spec::abi::Abi::RustIntrinsic;
884         if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
885             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind))
886         {
887             if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
888                 let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
889                                consider instead using an UnsafeCell";
890                 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit());
891             }
892         }
893
894         fn get_transmute_from_to<'a, 'tcx>(
895             cx: &LateContext<'a, 'tcx>,
896             expr: &hir::Expr<'_>,
897         ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
898             let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
899                 cx.tables.qpath_res(qpath, expr.hir_id)
900             } else {
901                 return None;
902             };
903             if let Res::Def(DefKind::Fn, did) = def {
904                 if !def_id_is_transmute(cx, did) {
905                     return None;
906                 }
907                 let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx);
908                 let from = sig.inputs().skip_binder()[0];
909                 let to = *sig.output().skip_binder();
910                 return Some((from, to));
911             }
912             None
913         }
914
915         fn def_id_is_transmute(cx: &LateContext<'_, '_>, def_id: DefId) -> bool {
916             cx.tcx.fn_sig(def_id).abi() == RustIntrinsic
917                 && cx.tcx.item_name(def_id) == sym::transmute
918         }
919     }
920 }
921
922 declare_lint! {
923     UNSTABLE_FEATURES,
924     Allow,
925     "enabling unstable features (deprecated. do not use)"
926 }
927
928 declare_lint_pass!(
929     /// Forbids using the `#[feature(...)]` attribute
930     UnstableFeatures => [UNSTABLE_FEATURES]
931 );
932
933 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
934     fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) {
935         if attr.check_name(sym::feature) {
936             if let Some(items) = attr.meta_item_list() {
937                 for item in items {
938                     ctx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
939                         lint.build("unstable feature").emit()
940                     });
941                 }
942             }
943         }
944     }
945 }
946
947 declare_lint! {
948     pub UNREACHABLE_PUB,
949     Allow,
950     "`pub` items not reachable from crate root"
951 }
952
953 declare_lint_pass!(
954     /// Lint for items marked `pub` that aren't reachable from other crates.
955     UnreachablePub => [UNREACHABLE_PUB]
956 );
957
958 impl UnreachablePub {
959     fn perform_lint(
960         &self,
961         cx: &LateContext<'_, '_>,
962         what: &str,
963         id: hir::HirId,
964         vis: &hir::Visibility<'_>,
965         span: Span,
966         exportable: bool,
967     ) {
968         let mut applicability = Applicability::MachineApplicable;
969         match vis.node {
970             hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => {
971                 if span.from_expansion() {
972                     applicability = Applicability::MaybeIncorrect;
973                 }
974                 let def_span = cx.tcx.sess.source_map().guess_head_span(span);
975                 cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
976                     let mut err = lint.build(&format!("unreachable `pub` {}", what));
977                     let replacement = if cx.tcx.features().crate_visibility_modifier {
978                         "crate"
979                     } else {
980                         "pub(crate)"
981                     }
982                     .to_owned();
983
984                     err.span_suggestion(
985                         vis.span,
986                         "consider restricting its visibility",
987                         replacement,
988                         applicability,
989                     );
990                     if exportable {
991                         err.help("or consider exporting it for use by other crates");
992                     }
993                     err.emit();
994                 });
995             }
996             _ => {}
997         }
998     }
999 }
1000
1001 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
1002     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
1003         self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true);
1004     }
1005
1006     fn check_foreign_item(
1007         &mut self,
1008         cx: &LateContext<'_, '_>,
1009         foreign_item: &hir::ForeignItem<'tcx>,
1010     ) {
1011         self.perform_lint(
1012             cx,
1013             "item",
1014             foreign_item.hir_id,
1015             &foreign_item.vis,
1016             foreign_item.span,
1017             true,
1018         );
1019     }
1020
1021     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &hir::StructField<'_>) {
1022         self.perform_lint(cx, "field", field.hir_id, &field.vis, field.span, false);
1023     }
1024
1025     fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplItem<'_>) {
1026         self.perform_lint(cx, "item", impl_item.hir_id, &impl_item.vis, impl_item.span, false);
1027     }
1028 }
1029
1030 declare_lint! {
1031     TYPE_ALIAS_BOUNDS,
1032     Warn,
1033     "bounds in type aliases are not enforced"
1034 }
1035
1036 declare_lint_pass!(
1037     /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1038     /// They are relevant when using associated types, but otherwise neither checked
1039     /// at definition site nor enforced at use site.
1040     TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1041 );
1042
1043 impl TypeAliasBounds {
1044     fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
1045         match *qpath {
1046             hir::QPath::TypeRelative(ref ty, _) => {
1047                 // If this is a type variable, we found a `T::Assoc`.
1048                 match ty.kind {
1049                     hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => match path.res {
1050                         Res::Def(DefKind::TyParam, _) => true,
1051                         _ => false,
1052                     },
1053                     _ => false,
1054                 }
1055             }
1056             hir::QPath::Resolved(..) => false,
1057         }
1058     }
1059
1060     fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut DiagnosticBuilder<'_>) {
1061         // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1062         // bound.  Let's see if this type does that.
1063
1064         // We use a HIR visitor to walk the type.
1065         use rustc_hir::intravisit::{self, Visitor};
1066         struct WalkAssocTypes<'a, 'db> {
1067             err: &'a mut DiagnosticBuilder<'db>,
1068         }
1069         impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
1070             type Map = intravisit::ErasedMap<'v>;
1071
1072             fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1073                 intravisit::NestedVisitorMap::None
1074             }
1075
1076             fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
1077                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
1078                     self.err.span_help(
1079                         span,
1080                         "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \
1081                          associated types in type aliases",
1082                     );
1083                 }
1084                 intravisit::walk_qpath(self, qpath, id, span)
1085             }
1086         }
1087
1088         // Let's go for a walk!
1089         let mut visitor = WalkAssocTypes { err };
1090         visitor.visit_ty(ty);
1091     }
1092 }
1093
1094 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
1095     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
1096         let (ty, type_alias_generics) = match item.kind {
1097             hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics),
1098             _ => return,
1099         };
1100         let mut suggested_changing_assoc_types = false;
1101         // There must not be a where clause
1102         if !type_alias_generics.where_clause.predicates.is_empty() {
1103             cx.lint(
1104                 TYPE_ALIAS_BOUNDS,
1105                 |lint| {
1106                     let mut err = lint.build("where clauses are not enforced in type aliases");
1107                     let spans: Vec<_> = type_alias_generics
1108                         .where_clause
1109                         .predicates
1110                         .iter()
1111                         .map(|pred| pred.span())
1112                         .collect();
1113                     err.set_span(spans);
1114                     err.span_suggestion(
1115                         type_alias_generics.where_clause.span_for_predicates_or_empty_place(),
1116                         "the clause will not be checked when the type alias is used, and should be removed",
1117                         String::new(),
1118                         Applicability::MachineApplicable,
1119                     );
1120                     if !suggested_changing_assoc_types {
1121                         TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1122                         suggested_changing_assoc_types = true;
1123                     }
1124                     err.emit();
1125                 },
1126             );
1127         }
1128         // The parameters must not have bounds
1129         for param in type_alias_generics.params.iter() {
1130             let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
1131             let suggestion = spans
1132                 .iter()
1133                 .map(|sp| {
1134                     let start = param.span.between(*sp); // Include the `:` in `T: Bound`.
1135                     (start.to(*sp), String::new())
1136                 })
1137                 .collect();
1138             if !spans.is_empty() {
1139                 cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| {
1140                     let mut err =
1141                         lint.build("bounds on generic parameters are not enforced in type aliases");
1142                     let msg = "the bound will not be checked when the type alias is used, \
1143                                    and should be removed";
1144                     err.multipart_suggestion(&msg, suggestion, Applicability::MachineApplicable);
1145                     if !suggested_changing_assoc_types {
1146                         TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1147                         suggested_changing_assoc_types = true;
1148                     }
1149                     err.emit();
1150                 });
1151             }
1152         }
1153     }
1154 }
1155
1156 declare_lint_pass!(
1157     /// Lint constants that are erroneous.
1158     /// Without this lint, we might not get any diagnostic if the constant is
1159     /// unused within this crate, even though downstream crates can't use it
1160     /// without producing an error.
1161     UnusedBrokenConst => []
1162 );
1163
1164 fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
1165     let def_id = cx.tcx.hir().body_owner_def_id(body_id);
1166     // trigger the query once for all constants since that will already report the errors
1167     // FIXME: Use ensure here
1168     let _ = cx.tcx.const_eval_poly(def_id);
1169 }
1170
1171 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {
1172     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
1173         match it.kind {
1174             hir::ItemKind::Const(_, body_id) => {
1175                 check_const(cx, body_id);
1176             }
1177             hir::ItemKind::Static(_, _, body_id) => {
1178                 check_const(cx, body_id);
1179             }
1180             _ => {}
1181         }
1182     }
1183 }
1184
1185 declare_lint! {
1186     TRIVIAL_BOUNDS,
1187     Warn,
1188     "these bounds don't depend on an type parameters"
1189 }
1190
1191 declare_lint_pass!(
1192     /// Lint for trait and lifetime bounds that don't depend on type parameters
1193     /// which either do nothing, or stop the item from being used.
1194     TrivialConstraints => [TRIVIAL_BOUNDS]
1195 );
1196
1197 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
1198     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>) {
1199         use rustc_middle::ty::fold::TypeFoldable;
1200         use rustc_middle::ty::Predicate::*;
1201
1202         if cx.tcx.features().trivial_bounds {
1203             let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1204             let predicates = cx.tcx.predicates_of(def_id);
1205             for &(predicate, span) in predicates.predicates {
1206                 let predicate_kind_name = match predicate {
1207                     Trait(..) => "Trait",
1208                     TypeOutlives(..) |
1209                     RegionOutlives(..) => "Lifetime",
1210
1211                     // Ignore projections, as they can only be global
1212                     // if the trait bound is global
1213                     Projection(..) |
1214                     // Ignore bounds that a user can't type
1215                     WellFormed(..) |
1216                     ObjectSafe(..) |
1217                     ClosureKind(..) |
1218                     Subtype(..) |
1219                     ConstEvaluatable(..) => continue,
1220                 };
1221                 if predicate.is_global() {
1222                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
1223                         lint.build(&format!(
1224                             "{} bound {} does not depend on any type \
1225                                 or lifetime parameters",
1226                             predicate_kind_name, predicate
1227                         ))
1228                         .emit()
1229                     });
1230                 }
1231             }
1232         }
1233     }
1234 }
1235
1236 declare_lint_pass!(
1237     /// Does nothing as a lint pass, but registers some `Lint`s
1238     /// which are used by other parts of the compiler.
1239     SoftLints => [
1240         WHILE_TRUE,
1241         BOX_POINTERS,
1242         NON_SHORTHAND_FIELD_PATTERNS,
1243         UNSAFE_CODE,
1244         MISSING_DOCS,
1245         MISSING_COPY_IMPLEMENTATIONS,
1246         MISSING_DEBUG_IMPLEMENTATIONS,
1247         ANONYMOUS_PARAMETERS,
1248         UNUSED_DOC_COMMENTS,
1249         NO_MANGLE_CONST_ITEMS,
1250         NO_MANGLE_GENERIC_ITEMS,
1251         MUTABLE_TRANSMUTES,
1252         UNSTABLE_FEATURES,
1253         UNREACHABLE_PUB,
1254         TYPE_ALIAS_BOUNDS,
1255         TRIVIAL_BOUNDS
1256     ]
1257 );
1258
1259 declare_lint! {
1260     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1261     Warn,
1262     "`...` range patterns are deprecated"
1263 }
1264
1265 #[derive(Default)]
1266 pub struct EllipsisInclusiveRangePatterns {
1267     /// If `Some(_)`, suppress all subsequent pattern
1268     /// warnings for better diagnostics.
1269     node_id: Option<ast::NodeId>,
1270 }
1271
1272 impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1273
1274 impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1275     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1276         if self.node_id.is_some() {
1277             // Don't recursively warn about patterns inside range endpoints.
1278             return;
1279         }
1280
1281         use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot};
1282
1283         /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1284         /// corresponding to the ellipsis.
1285         fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1286             match &pat.kind {
1287                 PatKind::Range(
1288                     a,
1289                     Some(b),
1290                     Spanned { span, node: RangeEnd::Included(DotDotDot) },
1291                 ) => Some((a.as_deref(), b, *span)),
1292                 _ => None,
1293             }
1294         }
1295
1296         let (parenthesise, endpoints) = match &pat.kind {
1297             PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
1298             _ => (false, matches_ellipsis_pat(pat)),
1299         };
1300
1301         if let Some((start, end, join)) = endpoints {
1302             let msg = "`...` range patterns are deprecated";
1303             let suggestion = "use `..=` for an inclusive range";
1304             if parenthesise {
1305                 self.node_id = Some(pat.id);
1306                 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
1307                     let end = expr_to_string(&end);
1308                     let replace = match start {
1309                         Some(start) => format!("&({}..={})", expr_to_string(&start), end),
1310                         None => format!("&(..={})", end),
1311                     };
1312                     lint.build(msg)
1313                         .span_suggestion(
1314                             pat.span,
1315                             suggestion,
1316                             replace,
1317                             Applicability::MachineApplicable,
1318                         )
1319                         .emit();
1320                 });
1321             } else {
1322                 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
1323                     lint.build(msg)
1324                         .span_suggestion_short(
1325                             join,
1326                             suggestion,
1327                             "..=".to_owned(),
1328                             Applicability::MachineApplicable,
1329                         )
1330                         .emit();
1331                 });
1332             };
1333         }
1334     }
1335
1336     fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1337         if let Some(node_id) = self.node_id {
1338             if pat.id == node_id {
1339                 self.node_id = None
1340             }
1341         }
1342     }
1343 }
1344
1345 declare_lint! {
1346     UNNAMEABLE_TEST_ITEMS,
1347     Warn,
1348     "detects an item that cannot be named being marked as `#[test_case]`",
1349     report_in_external_macro
1350 }
1351
1352 pub struct UnnameableTestItems {
1353     boundary: hir::HirId, // HirId of the item under which things are not nameable
1354     items_nameable: bool,
1355 }
1356
1357 impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1358
1359 impl UnnameableTestItems {
1360     pub fn new() -> Self {
1361         Self { boundary: hir::DUMMY_HIR_ID, items_nameable: true }
1362     }
1363 }
1364
1365 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
1366     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
1367         if self.items_nameable {
1368             if let hir::ItemKind::Mod(..) = it.kind {
1369             } else {
1370                 self.items_nameable = false;
1371                 self.boundary = it.hir_id;
1372             }
1373             return;
1374         }
1375
1376         if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
1377             cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
1378                 lint.build("cannot test inner items").emit()
1379             });
1380         }
1381     }
1382
1383     fn check_item_post(&mut self, _cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
1384         if !self.items_nameable && self.boundary == it.hir_id {
1385             self.items_nameable = true;
1386         }
1387     }
1388 }
1389
1390 declare_lint! {
1391     pub KEYWORD_IDENTS,
1392     Allow,
1393     "detects edition keywords being used as an identifier",
1394     @future_incompatible = FutureIncompatibleInfo {
1395         reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1396         edition: Some(Edition::Edition2018),
1397     };
1398 }
1399
1400 declare_lint_pass!(
1401     /// Check for uses of edition keywords used as an identifier.
1402     KeywordIdents => [KEYWORD_IDENTS]
1403 );
1404
1405 struct UnderMacro(bool);
1406
1407 impl KeywordIdents {
1408     fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
1409         for tt in tokens.into_trees() {
1410             match tt {
1411                 // Only report non-raw idents.
1412                 TokenTree::Token(token) => {
1413                     if let Some((ident, false)) = token.ident() {
1414                         self.check_ident_token(cx, UnderMacro(true), ident);
1415                     }
1416                 }
1417                 TokenTree::Delimited(_, _, tts) => self.check_tokens(cx, tts),
1418             }
1419         }
1420     }
1421
1422     fn check_ident_token(
1423         &mut self,
1424         cx: &EarlyContext<'_>,
1425         UnderMacro(under_macro): UnderMacro,
1426         ident: ast::Ident,
1427     ) {
1428         let next_edition = match cx.sess.edition() {
1429             Edition::Edition2015 => {
1430                 match ident.name {
1431                     kw::Async | kw::Await | kw::Try => Edition::Edition2018,
1432
1433                     // rust-lang/rust#56327: Conservatively do not
1434                     // attempt to report occurrences of `dyn` within
1435                     // macro definitions or invocations, because `dyn`
1436                     // can legitimately occur as a contextual keyword
1437                     // in 2015 code denoting its 2018 meaning, and we
1438                     // do not want rustfix to inject bugs into working
1439                     // code by rewriting such occurrences.
1440                     //
1441                     // But if we see `dyn` outside of a macro, we know
1442                     // its precise role in the parsed AST and thus are
1443                     // assured this is truly an attempt to use it as
1444                     // an identifier.
1445                     kw::Dyn if !under_macro => Edition::Edition2018,
1446
1447                     _ => return,
1448                 }
1449             }
1450
1451             // There are no new keywords yet for the 2018 edition and beyond.
1452             _ => return,
1453         };
1454
1455         // Don't lint `r#foo`.
1456         if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1457             return;
1458         }
1459
1460         cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
1461             lint.build(&format!("`{}` is a keyword in the {} edition", ident, next_edition))
1462                 .span_suggestion(
1463                     ident.span,
1464                     "you can use a raw identifier to stay compatible",
1465                     format!("r#{}", ident),
1466                     Applicability::MachineApplicable,
1467                 )
1468                 .emit()
1469         });
1470     }
1471 }
1472
1473 impl EarlyLintPass for KeywordIdents {
1474     fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
1475         self.check_tokens(cx, mac_def.body.inner_tokens());
1476     }
1477     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
1478         self.check_tokens(cx, mac.args.inner_tokens());
1479     }
1480     fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
1481         self.check_ident_token(cx, UnderMacro(false), ident);
1482     }
1483 }
1484
1485 declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
1486
1487 impl ExplicitOutlivesRequirements {
1488     fn lifetimes_outliving_lifetime<'tcx>(
1489         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
1490         index: u32,
1491     ) -> Vec<ty::Region<'tcx>> {
1492         inferred_outlives
1493             .iter()
1494             .filter_map(|(pred, _)| match pred {
1495                 ty::Predicate::RegionOutlives(outlives) => {
1496                     let outlives = outlives.skip_binder();
1497                     match outlives.0 {
1498                         ty::ReEarlyBound(ebr) if ebr.index == index => Some(outlives.1),
1499                         _ => None,
1500                     }
1501                 }
1502                 _ => None,
1503             })
1504             .collect()
1505     }
1506
1507     fn lifetimes_outliving_type<'tcx>(
1508         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
1509         index: u32,
1510     ) -> Vec<ty::Region<'tcx>> {
1511         inferred_outlives
1512             .iter()
1513             .filter_map(|(pred, _)| match pred {
1514                 ty::Predicate::TypeOutlives(outlives) => {
1515                     let outlives = outlives.skip_binder();
1516                     outlives.0.is_param(index).then_some(outlives.1)
1517                 }
1518                 _ => None,
1519             })
1520             .collect()
1521     }
1522
1523     fn collect_outlived_lifetimes<'tcx>(
1524         &self,
1525         param: &'tcx hir::GenericParam<'tcx>,
1526         tcx: TyCtxt<'tcx>,
1527         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
1528         ty_generics: &'tcx ty::Generics,
1529     ) -> Vec<ty::Region<'tcx>> {
1530         let index = ty_generics.param_def_id_to_index[&tcx.hir().local_def_id(param.hir_id)];
1531
1532         match param.kind {
1533             hir::GenericParamKind::Lifetime { .. } => {
1534                 Self::lifetimes_outliving_lifetime(inferred_outlives, index)
1535             }
1536             hir::GenericParamKind::Type { .. } => {
1537                 Self::lifetimes_outliving_type(inferred_outlives, index)
1538             }
1539             hir::GenericParamKind::Const { .. } => Vec::new(),
1540         }
1541     }
1542
1543     fn collect_outlives_bound_spans<'tcx>(
1544         &self,
1545         tcx: TyCtxt<'tcx>,
1546         bounds: &hir::GenericBounds<'_>,
1547         inferred_outlives: &[ty::Region<'tcx>],
1548         infer_static: bool,
1549     ) -> Vec<(usize, Span)> {
1550         use rustc_middle::middle::resolve_lifetime::Region;
1551
1552         bounds
1553             .iter()
1554             .enumerate()
1555             .filter_map(|(i, bound)| {
1556                 if let hir::GenericBound::Outlives(lifetime) = bound {
1557                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
1558                         Some(Region::Static) if infer_static => inferred_outlives
1559                             .iter()
1560                             .any(|r| if let ty::ReStatic = r { true } else { false }),
1561                         Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
1562                             if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false }
1563                         }),
1564                         _ => false,
1565                     };
1566                     is_inferred.then_some((i, bound.span()))
1567                 } else {
1568                     None
1569                 }
1570             })
1571             .collect()
1572     }
1573
1574     fn consolidate_outlives_bound_spans(
1575         &self,
1576         lo: Span,
1577         bounds: &hir::GenericBounds<'_>,
1578         bound_spans: Vec<(usize, Span)>,
1579     ) -> Vec<Span> {
1580         if bounds.is_empty() {
1581             return Vec::new();
1582         }
1583         if bound_spans.len() == bounds.len() {
1584             let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
1585             // If all bounds are inferable, we want to delete the colon, so
1586             // start from just after the parameter (span passed as argument)
1587             vec![lo.to(last_bound_span)]
1588         } else {
1589             let mut merged = Vec::new();
1590             let mut last_merged_i = None;
1591
1592             let mut from_start = true;
1593             for (i, bound_span) in bound_spans {
1594                 match last_merged_i {
1595                     // If the first bound is inferable, our span should also eat the leading `+`.
1596                     None if i == 0 => {
1597                         merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
1598                         last_merged_i = Some(0);
1599                     }
1600                     // If consecutive bounds are inferable, merge their spans
1601                     Some(h) if i == h + 1 => {
1602                         if let Some(tail) = merged.last_mut() {
1603                             // Also eat the trailing `+` if the first
1604                             // more-than-one bound is inferable
1605                             let to_span = if from_start && i < bounds.len() {
1606                                 bounds[i + 1].span().shrink_to_lo()
1607                             } else {
1608                                 bound_span
1609                             };
1610                             *tail = tail.to(to_span);
1611                             last_merged_i = Some(i);
1612                         } else {
1613                             bug!("another bound-span visited earlier");
1614                         }
1615                     }
1616                     _ => {
1617                         // When we find a non-inferable bound, subsequent inferable bounds
1618                         // won't be consecutive from the start (and we'll eat the leading
1619                         // `+` rather than the trailing one)
1620                         from_start = false;
1621                         merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
1622                         last_merged_i = Some(i);
1623                     }
1624                 }
1625             }
1626             merged
1627         }
1628     }
1629 }
1630
1631 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
1632     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
1633         use rustc_middle::middle::resolve_lifetime::Region;
1634
1635         let infer_static = cx.tcx.features().infer_static_outlives_requirements;
1636         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1637         if let hir::ItemKind::Struct(_, ref hir_generics)
1638         | hir::ItemKind::Enum(_, ref hir_generics)
1639         | hir::ItemKind::Union(_, ref hir_generics) = item.kind
1640         {
1641             let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
1642             if inferred_outlives.is_empty() {
1643                 return;
1644             }
1645
1646             let ty_generics = cx.tcx.generics_of(def_id);
1647
1648             let mut bound_count = 0;
1649             let mut lint_spans = Vec::new();
1650
1651             for param in hir_generics.params {
1652                 let has_lifetime_bounds = param.bounds.iter().any(|bound| {
1653                     if let hir::GenericBound::Outlives(_) = bound { true } else { false }
1654                 });
1655                 if !has_lifetime_bounds {
1656                     continue;
1657                 }
1658
1659                 let relevant_lifetimes =
1660                     self.collect_outlived_lifetimes(param, cx.tcx, inferred_outlives, ty_generics);
1661                 if relevant_lifetimes.is_empty() {
1662                     continue;
1663                 }
1664
1665                 let bound_spans = self.collect_outlives_bound_spans(
1666                     cx.tcx,
1667                     &param.bounds,
1668                     &relevant_lifetimes,
1669                     infer_static,
1670                 );
1671                 bound_count += bound_spans.len();
1672                 lint_spans.extend(self.consolidate_outlives_bound_spans(
1673                     param.span.shrink_to_hi(),
1674                     &param.bounds,
1675                     bound_spans,
1676                 ));
1677             }
1678
1679             let mut where_lint_spans = Vec::new();
1680             let mut dropped_predicate_count = 0;
1681             let num_predicates = hir_generics.where_clause.predicates.len();
1682             for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() {
1683                 let (relevant_lifetimes, bounds, span) = match where_predicate {
1684                     hir::WherePredicate::RegionPredicate(predicate) => {
1685                         if let Some(Region::EarlyBound(index, ..)) =
1686                             cx.tcx.named_region(predicate.lifetime.hir_id)
1687                         {
1688                             (
1689                                 Self::lifetimes_outliving_lifetime(inferred_outlives, index),
1690                                 &predicate.bounds,
1691                                 predicate.span,
1692                             )
1693                         } else {
1694                             continue;
1695                         }
1696                     }
1697                     hir::WherePredicate::BoundPredicate(predicate) => {
1698                         // FIXME we can also infer bounds on associated types,
1699                         // and should check for them here.
1700                         match predicate.bounded_ty.kind {
1701                             hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
1702                                 if let Res::Def(DefKind::TyParam, def_id) = path.res {
1703                                     let index = ty_generics.param_def_id_to_index[&def_id];
1704                                     (
1705                                         Self::lifetimes_outliving_type(inferred_outlives, index),
1706                                         &predicate.bounds,
1707                                         predicate.span,
1708                                     )
1709                                 } else {
1710                                     continue;
1711                                 }
1712                             }
1713                             _ => {
1714                                 continue;
1715                             }
1716                         }
1717                     }
1718                     _ => continue,
1719                 };
1720                 if relevant_lifetimes.is_empty() {
1721                     continue;
1722                 }
1723
1724                 let bound_spans = self.collect_outlives_bound_spans(
1725                     cx.tcx,
1726                     bounds,
1727                     &relevant_lifetimes,
1728                     infer_static,
1729                 );
1730                 bound_count += bound_spans.len();
1731
1732                 let drop_predicate = bound_spans.len() == bounds.len();
1733                 if drop_predicate {
1734                     dropped_predicate_count += 1;
1735                 }
1736
1737                 // If all the bounds on a predicate were inferable and there are
1738                 // further predicates, we want to eat the trailing comma.
1739                 if drop_predicate && i + 1 < num_predicates {
1740                     let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span();
1741                     where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
1742                 } else {
1743                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
1744                         span.shrink_to_lo(),
1745                         bounds,
1746                         bound_spans,
1747                     ));
1748                 }
1749             }
1750
1751             // If all predicates are inferable, drop the entire clause
1752             // (including the `where`)
1753             if num_predicates > 0 && dropped_predicate_count == num_predicates {
1754                 let where_span = hir_generics
1755                     .where_clause
1756                     .span()
1757                     .expect("span of (nonempty) where clause should exist");
1758                 // Extend the where clause back to the closing `>` of the
1759                 // generics, except for tuple struct, which have the `where`
1760                 // after the fields of the struct.
1761                 let full_where_span =
1762                     if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
1763                         where_span
1764                     } else {
1765                         hir_generics.span.shrink_to_hi().to(where_span)
1766                     };
1767                 lint_spans.push(full_where_span);
1768             } else {
1769                 lint_spans.extend(where_lint_spans);
1770             }
1771
1772             if !lint_spans.is_empty() {
1773                 cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
1774                     lint.build("outlives requirements can be inferred")
1775                         .multipart_suggestion(
1776                             if bound_count == 1 {
1777                                 "remove this bound"
1778                             } else {
1779                                 "remove these bounds"
1780                             },
1781                             lint_spans
1782                                 .into_iter()
1783                                 .map(|span| (span, "".to_owned()))
1784                                 .collect::<Vec<_>>(),
1785                             Applicability::MachineApplicable,
1786                         )
1787                         .emit();
1788                 });
1789             }
1790         }
1791     }
1792 }
1793
1794 declare_lint! {
1795     pub INCOMPLETE_FEATURES,
1796     Warn,
1797     "incomplete features that may function improperly in some or all cases"
1798 }
1799
1800 declare_lint_pass!(
1801     /// Check for used feature gates in `INCOMPLETE_FEATURES` in `librustc_feature/active.rs`.
1802     IncompleteFeatures => [INCOMPLETE_FEATURES]
1803 );
1804
1805 impl EarlyLintPass for IncompleteFeatures {
1806     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
1807         let features = cx.sess.features_untracked();
1808         features
1809             .declared_lang_features
1810             .iter()
1811             .map(|(name, span, _)| (name, span))
1812             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
1813             .filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
1814             .for_each(|(name, &span)| {
1815                 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
1816                     lint.build(&format!(
1817                         "the feature `{}` is incomplete and may cause the compiler to crash",
1818                         name,
1819                     ))
1820                     .emit()
1821                 })
1822             });
1823     }
1824 }
1825
1826 declare_lint! {
1827     pub INVALID_VALUE,
1828     Warn,
1829     "an invalid value is being created (such as a NULL reference)"
1830 }
1831
1832 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
1833
1834 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
1835     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>) {
1836         #[derive(Debug, Copy, Clone, PartialEq)]
1837         enum InitKind {
1838             Zeroed,
1839             Uninit,
1840         };
1841
1842         /// Information about why a type cannot be initialized this way.
1843         /// Contains an error message and optionally a span to point at.
1844         type InitError = (String, Option<Span>);
1845
1846         /// Test if this constant is all-0.
1847         fn is_zero(expr: &hir::Expr<'_>) -> bool {
1848             use hir::ExprKind::*;
1849             use rustc_ast::ast::LitKind::*;
1850             match &expr.kind {
1851                 Lit(lit) => {
1852                     if let Int(i, _) = lit.node {
1853                         i == 0
1854                     } else {
1855                         false
1856                     }
1857                 }
1858                 Tup(tup) => tup.iter().all(is_zero),
1859                 _ => false,
1860             }
1861         }
1862
1863         /// Determine if this expression is a "dangerous initialization".
1864         fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
1865             // `transmute` is inside an anonymous module (the `extern` block?);
1866             // `Invalid` represents the empty string and matches that.
1867             // FIXME(#66075): use diagnostic items.  Somehow, that does not seem to work
1868             // on intrinsics right now.
1869             const TRANSMUTE_PATH: &[Symbol] =
1870                 &[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];
1871
1872             if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
1873                 // Find calls to `mem::{uninitialized,zeroed}` methods.
1874                 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
1875                     let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
1876
1877                     if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
1878                         return Some(InitKind::Zeroed);
1879                     } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) {
1880                         return Some(InitKind::Uninit);
1881                     } else if cx.match_def_path(def_id, TRANSMUTE_PATH) {
1882                         if is_zero(&args[0]) {
1883                             return Some(InitKind::Zeroed);
1884                         }
1885                     }
1886                 }
1887             } else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind {
1888                 // Find problematic calls to `MaybeUninit::assume_init`.
1889                 let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
1890                 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
1891                     // This is a call to *some* method named `assume_init`.
1892                     // See if the `self` parameter is one of the dangerous constructors.
1893                     if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
1894                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
1895                             let def_id =
1896                                 cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
1897
1898                             if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
1899                                 return Some(InitKind::Zeroed);
1900                             } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
1901                                 return Some(InitKind::Uninit);
1902                             }
1903                         }
1904                     }
1905                 }
1906             }
1907
1908             None
1909         }
1910
1911         /// Return `Some` only if we are sure this type does *not*
1912         /// allow zero initialization.
1913         fn ty_find_init_error<'tcx>(
1914             tcx: TyCtxt<'tcx>,
1915             ty: Ty<'tcx>,
1916             init: InitKind,
1917         ) -> Option<InitError> {
1918             use rustc_middle::ty::TyKind::*;
1919             match ty.kind {
1920                 // Primitive types that don't like 0 as a value.
1921                 Ref(..) => Some(("references must be non-null".to_string(), None)),
1922                 Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)),
1923                 FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)),
1924                 Never => Some(("the `!` type has no valid value".to_string(), None)),
1925                 RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) =>
1926                 // raw ptr to dyn Trait
1927                 {
1928                     Some(("the vtable of a wide raw pointer must be non-null".to_string(), None))
1929                 }
1930                 // Primitive types with other constraints.
1931                 Bool if init == InitKind::Uninit => {
1932                     Some(("booleans must be either `true` or `false`".to_string(), None))
1933                 }
1934                 Char if init == InitKind::Uninit => {
1935                     Some(("characters must be a valid Unicode codepoint".to_string(), None))
1936                 }
1937                 // Recurse and checks for some compound types.
1938                 Adt(adt_def, substs) if !adt_def.is_union() => {
1939                     // First check f this ADT has a layout attribute (like `NonNull` and friends).
1940                     use std::ops::Bound;
1941                     match tcx.layout_scalar_valid_range(adt_def.did) {
1942                         // We exploit here that `layout_scalar_valid_range` will never
1943                         // return `Bound::Excluded`.  (And we have tests checking that we
1944                         // handle the attribute correctly.)
1945                         (Bound::Included(lo), _) if lo > 0 => {
1946                             return Some((format!("`{}` must be non-null", ty), None));
1947                         }
1948                         (Bound::Included(_), _) | (_, Bound::Included(_))
1949                             if init == InitKind::Uninit =>
1950                         {
1951                             return Some((
1952                                 format!(
1953                                     "`{}` must be initialized inside its custom valid range",
1954                                     ty,
1955                                 ),
1956                                 None,
1957                             ));
1958                         }
1959                         _ => {}
1960                     }
1961                     // Now, recurse.
1962                     match adt_def.variants.len() {
1963                         0 => Some(("enums with no variants have no valid value".to_string(), None)),
1964                         1 => {
1965                             // Struct, or enum with exactly one variant.
1966                             // Proceed recursively, check all fields.
1967                             let variant = &adt_def.variants[VariantIdx::from_u32(0)];
1968                             variant.fields.iter().find_map(|field| {
1969                                 ty_find_init_error(tcx, field.ty(tcx, substs), init).map(
1970                                     |(mut msg, span)| {
1971                                         if span.is_none() {
1972                                             // Point to this field, should be helpful for figuring
1973                                             // out where the source of the error is.
1974                                             let span = tcx.def_span(field.did);
1975                                             write!(
1976                                                 &mut msg,
1977                                                 " (in this {} field)",
1978                                                 adt_def.descr()
1979                                             )
1980                                             .unwrap();
1981                                             (msg, Some(span))
1982                                         } else {
1983                                             // Just forward.
1984                                             (msg, span)
1985                                         }
1986                                     },
1987                                 )
1988                             })
1989                         }
1990                         // Multi-variant enums are tricky: if all but one variant are
1991                         // uninhabited, we might actually do layout like for a single-variant
1992                         // enum, and then even leaving them uninitialized could be okay.
1993                         _ => None, // Conservative fallback for multi-variant enum.
1994                     }
1995                 }
1996                 Tuple(..) => {
1997                     // Proceed recursively, check all fields.
1998                     ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field, init))
1999                 }
2000                 // Conservative fallback.
2001                 _ => None,
2002             }
2003         }
2004
2005         if let Some(init) = is_dangerous_init(cx, expr) {
2006             // This conjures an instance of a type out of nothing,
2007             // using zeroed or uninitialized memory.
2008             // We are extremely conservative with what we warn about.
2009             let conjured_ty = cx.tables.expr_ty(expr);
2010             if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
2011                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
2012                     let mut err = lint.build(&format!(
2013                         "the type `{}` does not permit {}",
2014                         conjured_ty,
2015                         match init {
2016                             InitKind::Zeroed => "zero-initialization",
2017                             InitKind::Uninit => "being left uninitialized",
2018                         },
2019                     ));
2020                     err.span_label(expr.span, "this code causes undefined behavior when executed");
2021                     err.span_label(
2022                         expr.span,
2023                         "help: use `MaybeUninit<T>` instead, \
2024                             and only call `assume_init` after initialization is done",
2025                     );
2026                     if let Some(span) = span {
2027                         err.span_note(span, &msg);
2028                     } else {
2029                         err.note(&msg);
2030                     }
2031                     err.emit();
2032                 });
2033             }
2034         }
2035     }
2036 }