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