1 //! Lints in the Rust compiler.
3 //! This contains lints which can feasibly be implemented as their own
4 //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
5 //! definitions of lints that are emitted directly inside the main compiler.
7 //! To add a new lint to rustc, declare it here using `declare_lint!()`.
8 //! Then add code to emit the new lint in the appropriate circumstances.
9 //! You can do that in an existing `LintPass` if it makes sense, or in a
10 //! new `LintPass`, or using `Session::add_lint` elsewhere in the
11 //! compiler. Only do the latter if the check can't be written cleanly as a
12 //! `LintPass` (also, note that such lints will need to be defined in
13 //! `rustc_session::lint::builtin`, not here).
15 //! If you define a new `EarlyLintPass`, you will also need to add it to the
16 //! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
17 //! `lib.rs`. Use the former for unit-like structs and the latter for structs
18 //! with a `pub fn new()`.
20 //! If you define a new `LateLintPass`, you will also need to add it to the
21 //! `late_lint_methods!` invocation in `lib.rs`.
24 errors::BuiltinEllpisisInclusiveRangePatterns,
25 types::{transparent_newtype_field, CItemKind},
26 EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
29 use rustc_ast::tokenstream::{TokenStream, TokenTree};
30 use rustc_ast::visit::{FnCtxt, FnKind};
31 use rustc_ast::{self as ast, *};
32 use rustc_ast_pretty::pprust::{self, expr_to_string};
33 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
34 use rustc_data_structures::stack::ensure_sufficient_stack;
36 fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
37 LintDiagnosticBuilder, MultiSpan,
39 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
41 use rustc_hir::def::{DefKind, Res};
42 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
43 use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
44 use rustc_index::vec::Idx;
45 use rustc_middle::lint::in_external_macro;
46 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
47 use rustc_middle::ty::print::with_no_trimmed_paths;
48 use rustc_middle::ty::subst::GenericArgKind;
49 use rustc_middle::ty::Instance;
50 use rustc_middle::ty::{self, Ty, TyCtxt};
51 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
52 use rustc_span::edition::Edition;
53 use rustc_span::source_map::Spanned;
54 use rustc_span::symbol::{kw, sym, Ident, Symbol};
55 use rustc_span::{BytePos, InnerSpan, Span};
56 use rustc_target::abi::VariantIdx;
57 use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
59 use crate::nonstandard_style::{method_context, MethodLateContext};
63 // hardwired lints from librustc_middle
64 pub use rustc_session::lint::builtin::*;
67 /// The `while_true` lint detects `while true { }`.
81 /// `while true` should be replaced with `loop`. A `loop` expression is
82 /// the preferred way to write an infinite loop because it more directly
83 /// expresses the intent of the loop.
86 "suggest using `loop { }` instead of `while true { }`"
89 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
91 /// Traverse through any amount of parenthesis and return the first non-parens expression.
92 fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
93 while let ast::ExprKind::Paren(sub) = &expr.kind {
99 impl EarlyLintPass for WhileTrue {
100 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
101 if let ast::ExprKind::While(cond, _, label) = &e.kind {
102 if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
103 if let ast::LitKind::Bool(true) = lit.kind {
104 if !lit.span.from_expansion() {
105 let condition_span = e.span.with_hi(cond.span.hi());
106 cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
107 lint.build(fluent::lint::builtin_while_true)
108 .span_suggestion_short(
110 fluent::lint::suggestion,
113 label.map_or_else(String::new, |label| format!(
118 Applicability::MachineApplicable,
130 /// The `box_pointers` lints use of the Box type.
134 /// ```rust,compile_fail
135 /// #![deny(box_pointers)]
145 /// This lint is mostly historical, and not particularly useful. `Box<T>`
146 /// used to be built into the language, and the only way to do heap
147 /// allocation. Today's Rust can call into other allocators, etc.
150 "use of owned (Box type) heap memory"
153 declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
156 fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
157 for leaf in ty.walk() {
158 if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
159 if leaf_ty.is_box() {
160 cx.struct_span_lint(BOX_POINTERS, span, |lint| {
161 lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
169 impl<'tcx> LateLintPass<'tcx> for BoxPointers {
170 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
172 hir::ItemKind::Fn(..)
173 | hir::ItemKind::TyAlias(..)
174 | hir::ItemKind::Enum(..)
175 | hir::ItemKind::Struct(..)
176 | hir::ItemKind::Union(..) => {
177 self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
182 // If it's a struct, we also have to check the fields' types
184 hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
185 for struct_field in struct_def.fields() {
186 let def_id = cx.tcx.hir().local_def_id(struct_field.hir_id);
187 self.check_heap_type(cx, struct_field.span, cx.tcx.type_of(def_id));
194 fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
195 let ty = cx.typeck_results().node_type(e.hir_id);
196 self.check_heap_type(cx, e.span, ty);
201 /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
202 /// instead of `Struct { x }` in a pattern.
220 /// Point { x: x, y: y } => (),
229 /// The preferred style is to avoid the repetition of specifying both the
230 /// field name and the binding name if both identifiers are the same.
231 NON_SHORTHAND_FIELD_PATTERNS,
233 "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
236 declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
238 impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
239 fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
240 if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
245 .expect("struct pattern type is not an ADT")
246 .variant_of_res(cx.qpath_res(qpath, pat.hir_id));
247 for fieldpat in field_pats {
248 if fieldpat.is_shorthand {
251 if fieldpat.span.from_expansion() {
252 // Don't lint if this is a macro expansion: macro authors
253 // shouldn't have to worry about this kind of style issue
257 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
258 if cx.tcx.find_field_index(ident, &variant)
259 == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
261 cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
262 let suggested_ident =
263 format!("{}{}", binding_annot.prefix_str(), ident);
264 lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
265 .set_arg("ident", ident.clone())
268 fluent::lint::suggestion,
270 Applicability::MachineApplicable,
282 /// The `unsafe_code` lint catches usage of `unsafe` code.
286 /// ```rust,compile_fail
287 /// #![deny(unsafe_code)]
299 /// This lint is intended to restrict the usage of `unsafe`, which can be
300 /// difficult to use correctly.
303 "usage of `unsafe` code"
306 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
311 cx: &EarlyContext<'_>,
313 decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
315 // This comes from a macro that has `#[allow_internal_unsafe]`.
316 if span.allows_unsafe() {
320 cx.struct_span_lint(UNSAFE_CODE, span, decorate);
323 fn report_overridden_symbol_name(
325 cx: &EarlyContext<'_>,
327 msg: DiagnosticMessage,
329 self.report_unsafe(cx, span, |lint| {
330 lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
334 fn report_overridden_symbol_section(
336 cx: &EarlyContext<'_>,
338 msg: DiagnosticMessage,
340 self.report_unsafe(cx, span, |lint| {
341 lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
346 impl EarlyLintPass for UnsafeCode {
347 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
348 if attr.has_name(sym::allow_internal_unsafe) {
349 self.report_unsafe(cx, attr.span, |lint| {
350 lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
355 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
356 if let ast::ExprKind::Block(ref blk, _) = e.kind {
357 // Don't warn about generated blocks; that'll just pollute the output.
358 if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
359 self.report_unsafe(cx, blk.span, |lint| {
360 lint.build(fluent::lint::builtin_unsafe_block).emit();
366 fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
368 ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
369 .report_unsafe(cx, it.span, |lint| {
370 lint.build(fluent::lint::builtin_unsafe_trait).emit();
373 ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
374 .report_unsafe(cx, it.span, |lint| {
375 lint.build(fluent::lint::builtin_unsafe_impl).emit();
378 ast::ItemKind::Fn(..) => {
379 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
380 self.report_overridden_symbol_name(
383 fluent::lint::builtin_no_mangle_fn,
387 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
388 self.report_overridden_symbol_name(
391 fluent::lint::builtin_export_name_fn,
395 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
396 self.report_overridden_symbol_section(
399 fluent::lint::builtin_link_section_fn,
404 ast::ItemKind::Static(..) => {
405 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
406 self.report_overridden_symbol_name(
409 fluent::lint::builtin_no_mangle_static,
413 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
414 self.report_overridden_symbol_name(
417 fluent::lint::builtin_export_name_static,
421 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
422 self.report_overridden_symbol_section(
425 fluent::lint::builtin_link_section_static,
434 fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
435 if let ast::AssocItemKind::Fn(..) = it.kind {
436 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
437 self.report_overridden_symbol_name(
440 fluent::lint::builtin_no_mangle_method,
443 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
444 self.report_overridden_symbol_name(
447 fluent::lint::builtin_export_name_method,
453 fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
457 ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
463 let msg = match ctxt {
464 FnCtxt::Foreign => return,
465 FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
466 FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
467 FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
469 self.report_unsafe(cx, span, |lint| {
470 lint.build(msg).emit();
477 /// The `missing_docs` lint detects missing documentation for public items.
481 /// ```rust,compile_fail
482 /// #![deny(missing_docs)]
490 /// This lint is intended to ensure that a library is well-documented.
491 /// Items without documentation can be difficult for users to understand
492 /// how to use properly.
494 /// This lint is "allow" by default because it can be noisy, and not all
495 /// projects may want to enforce everything to be documented.
498 "detects missing documentation for public members",
499 report_in_external_macro
502 pub struct MissingDoc {
503 /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
504 doc_hidden_stack: Vec<bool>,
507 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
509 fn has_doc(attr: &ast::Attribute) -> bool {
510 if attr.is_doc_comment() {
514 if !attr.has_name(sym::doc) {
518 if attr.value_str().is_some() {
522 if let Some(list) = attr.meta_item_list() {
524 if meta.has_name(sym::hidden) {
534 pub fn new() -> MissingDoc {
535 MissingDoc { doc_hidden_stack: vec![false] }
538 fn doc_hidden(&self) -> bool {
539 *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
542 fn check_missing_docs_attrs(
544 cx: &LateContext<'_>,
546 article: &'static str,
549 // If we're building a test harness, then warning about
550 // documentation is probably not really relevant right now.
551 if cx.sess().opts.test {
555 // `#[doc(hidden)]` disables missing_docs check.
556 if self.doc_hidden() {
560 // Only check publicly-visible items, using the result from the privacy pass.
561 // It's an option so the crate root can also use this function (it doesn't
563 if def_id != CRATE_DEF_ID {
564 if !cx.access_levels.is_exported(def_id) {
569 let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
570 let has_doc = attrs.iter().any(has_doc);
572 cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
573 lint.build(fluent::lint::builtin_missing_doc)
574 .set_arg("article", article)
575 .set_arg("desc", desc)
582 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
583 fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
584 let doc_hidden = self.doc_hidden()
585 || attrs.iter().any(|attr| {
586 attr.has_name(sym::doc)
587 && match attr.meta_item_list() {
589 Some(l) => attr::list_contains_name(&l, sym::hidden),
592 self.doc_hidden_stack.push(doc_hidden);
595 fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
596 self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
599 fn check_crate(&mut self, cx: &LateContext<'_>) {
600 self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
603 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
605 hir::ItemKind::Trait(..) => {
606 // Issue #11592: traits are always considered exported, even when private.
607 if cx.tcx.visibility(it.def_id)
608 == ty::Visibility::Restricted(
609 cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(),
615 hir::ItemKind::TyAlias(..)
616 | hir::ItemKind::Fn(..)
617 | hir::ItemKind::Macro(..)
618 | hir::ItemKind::Mod(..)
619 | hir::ItemKind::Enum(..)
620 | hir::ItemKind::Struct(..)
621 | hir::ItemKind::Union(..)
622 | hir::ItemKind::Const(..)
623 | hir::ItemKind::Static(..) => {}
628 let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
630 self.check_missing_docs_attrs(cx, it.def_id.def_id, article, desc);
633 fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
634 let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
636 self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc);
639 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
640 // If the method is an impl for a trait, don't doc.
641 if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl {
645 // If the method is an impl for an item with docs_hidden, don't doc.
646 if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
647 let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
648 let impl_ty = cx.tcx.type_of(parent);
649 let outerdef = match impl_ty.kind() {
650 ty::Adt(def, _) => Some(def.did()),
651 ty::Foreign(def_id) => Some(*def_id),
654 let is_hidden = match outerdef {
655 Some(id) => cx.tcx.is_doc_hidden(id),
663 let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
664 self.check_missing_docs_attrs(cx, impl_item.def_id.def_id, article, desc);
667 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
668 let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
669 self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc);
672 fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
673 if !sf.is_positional() {
674 let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
675 self.check_missing_docs_attrs(cx, def_id, "a", "struct field")
679 fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
680 self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), "a", "variant");
685 /// The `missing_copy_implementations` lint detects potentially-forgotten
686 /// implementations of [`Copy`].
688 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
692 /// ```rust,compile_fail
693 /// #![deny(missing_copy_implementations)]
704 /// Historically (before 1.0), types were automatically marked as `Copy`
705 /// if possible. This was changed so that it required an explicit opt-in
706 /// by implementing the `Copy` trait. As part of this change, a lint was
707 /// added to alert if a copyable type was not marked `Copy`.
709 /// This lint is "allow" by default because this code isn't bad; it is
710 /// common to write newtypes like this specifically so that a `Copy` type
711 /// is no longer `Copy`. `Copy` types can result in unintended copies of
712 /// large data which can impact performance.
713 pub MISSING_COPY_IMPLEMENTATIONS,
715 "detects potentially-forgotten implementations of `Copy`"
718 declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
720 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
721 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
722 if !cx.access_levels.is_reachable(item.def_id.def_id) {
725 let (def, ty) = match item.kind {
726 hir::ItemKind::Struct(_, ref ast_generics) => {
727 if !ast_generics.params.is_empty() {
730 let def = cx.tcx.adt_def(item.def_id);
731 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
733 hir::ItemKind::Union(_, ref ast_generics) => {
734 if !ast_generics.params.is_empty() {
737 let def = cx.tcx.adt_def(item.def_id);
738 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
740 hir::ItemKind::Enum(_, ref ast_generics) => {
741 if !ast_generics.params.is_empty() {
744 let def = cx.tcx.adt_def(item.def_id);
745 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
749 if def.has_dtor(cx.tcx) {
752 let param_env = ty::ParamEnv::empty();
753 if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
756 if can_type_implement_copy(
760 traits::ObligationCause::misc(item.span, item.hir_id()),
764 cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
765 lint.build(fluent::lint::builtin_missing_copy_impl).emit();
772 /// The `missing_debug_implementations` lint detects missing
773 /// implementations of [`fmt::Debug`].
775 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
779 /// ```rust,compile_fail
780 /// #![deny(missing_debug_implementations)]
789 /// Having a `Debug` implementation on all types can assist with
790 /// debugging, as it provides a convenient way to format and display a
791 /// value. Using the `#[derive(Debug)]` attribute will automatically
792 /// generate a typical implementation, or a custom implementation can be
793 /// added by manually implementing the `Debug` trait.
795 /// This lint is "allow" by default because adding `Debug` to all types can
796 /// have a negative impact on compile time and code size. It also requires
797 /// boilerplate to be added to every type, which can be an impediment.
798 MISSING_DEBUG_IMPLEMENTATIONS,
800 "detects missing implementations of Debug"
804 pub struct MissingDebugImplementations {
805 impling_types: Option<LocalDefIdSet>,
808 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
810 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
811 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
812 if !cx.access_levels.is_reachable(item.def_id.def_id) {
817 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
821 let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
825 if self.impling_types.is_none() {
826 let mut impls = LocalDefIdSet::default();
827 cx.tcx.for_each_impl(debug, |d| {
828 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
829 if let Some(def_id) = ty_def.did().as_local() {
830 impls.insert(def_id);
835 self.impling_types = Some(impls);
836 debug!("{:?}", self.impling_types);
839 if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
840 cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
841 lint.build(fluent::lint::builtin_missing_debug_impl)
842 .set_arg("debug", cx.tcx.def_path_str(debug))
850 /// The `anonymous_parameters` lint detects anonymous parameters in trait
855 /// ```rust,edition2015,compile_fail
856 /// #![deny(anonymous_parameters)]
868 /// This syntax is mostly a historical accident, and can be worked around
869 /// quite easily by adding an `_` pattern or a descriptive identifier:
873 /// fn foo(_: usize);
877 /// This syntax is now a hard error in the 2018 edition. In the 2015
878 /// edition, this lint is "warn" by default. This lint
879 /// enables the [`cargo fix`] tool with the `--edition` flag to
880 /// automatically transition old code from the 2015 edition to 2018. The
881 /// tool will run this lint and automatically apply the
882 /// suggested fix from the compiler (which is to add `_` to each
883 /// parameter). This provides a completely automated way to update old
884 /// code for a new edition. See [issue #41686] for more details.
886 /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
887 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
888 pub ANONYMOUS_PARAMETERS,
890 "detects anonymous parameters",
891 @future_incompatible = FutureIncompatibleInfo {
892 reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
893 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
898 /// Checks for use of anonymous parameters (RFC 1685).
899 AnonymousParameters => [ANONYMOUS_PARAMETERS]
902 impl EarlyLintPass for AnonymousParameters {
903 fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
904 if cx.sess().edition() != Edition::Edition2015 {
905 // This is a hard error in future editions; avoid linting and erroring
908 if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
909 for arg in sig.decl.inputs.iter() {
910 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
911 if ident.name == kw::Empty {
912 cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
913 let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
915 let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
916 (snip.as_str(), Applicability::MachineApplicable)
918 ("<type>", Applicability::HasPlaceholders)
921 lint.build(fluent::lint::builtin_anonymous_params)
924 fluent::lint::suggestion,
925 format!("_: {}", ty_snip),
937 /// Check for use of attributes which have been deprecated.
939 pub struct DeprecatedAttr {
940 // This is not free to compute, so we want to keep it around, rather than
941 // compute it for every attribute.
942 depr_attrs: Vec<&'static BuiltinAttribute>,
945 impl_lint_pass!(DeprecatedAttr => []);
947 impl DeprecatedAttr {
948 pub fn new() -> DeprecatedAttr {
949 DeprecatedAttr { depr_attrs: deprecated_attributes() }
953 impl EarlyLintPass for DeprecatedAttr {
954 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
955 for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
956 if attr.ident().map(|ident| ident.name) == Some(*name) {
957 if let &AttributeGate::Gated(
958 Stability::Deprecated(link, suggestion),
964 cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
965 // FIXME(davidtwco) translatable deprecated attr
966 lint.build(fluent::lint::builtin_deprecated_attr_link)
967 .set_arg("name", name)
968 .set_arg("reason", reason)
969 .set_arg("link", link)
970 .span_suggestion_short(
972 suggestion.map(|s| s.into()).unwrap_or(
973 fluent::lint::builtin_deprecated_attr_default_suggestion,
976 Applicability::MachineApplicable,
984 if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
985 cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
986 lint.build(fluent::lint::builtin_deprecated_attr_used)
987 .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
988 .span_suggestion_short(
990 fluent::lint::builtin_deprecated_attr_default_suggestion,
992 Applicability::MachineApplicable,
1000 fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
1001 use rustc_ast::token::CommentKind;
1003 let mut attrs = attrs.iter().peekable();
1005 // Accumulate a single span for sugared doc comments.
1006 let mut sugared_span: Option<Span> = None;
1008 while let Some(attr) = attrs.next() {
1009 let is_doc_comment = attr.is_doc_comment();
1012 Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
1015 if attrs.peek().map_or(false, |next_attr| next_attr.is_doc_comment()) {
1019 let span = sugared_span.take().unwrap_or(attr.span);
1021 if is_doc_comment || attr.has_name(sym::doc) {
1022 cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
1023 let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
1024 err.set_arg("kind", node_kind);
1025 err.span_label(node_span, fluent::lint::label);
1027 AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
1028 err.help(fluent::lint::plain_help);
1030 AttrKind::DocComment(CommentKind::Block, _) => {
1031 err.help(fluent::lint::block_help);
1040 impl EarlyLintPass for UnusedDocComment {
1041 fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
1042 let kind = match stmt.kind {
1043 ast::StmtKind::Local(..) => "statements",
1044 // Disabled pending discussion in #78306
1045 ast::StmtKind::Item(..) => return,
1046 // expressions will be reported by `check_expr`.
1047 ast::StmtKind::Empty
1048 | ast::StmtKind::Semi(_)
1049 | ast::StmtKind::Expr(_)
1050 | ast::StmtKind::MacCall(_) => return,
1053 warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
1056 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1057 let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
1058 warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1061 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1062 warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
1065 fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
1066 warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs);
1069 fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
1070 warn_if_doc(cx, block.span, "blocks", &block.attrs());
1073 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1074 if let ast::ItemKind::ForeignMod(_) = item.kind {
1075 warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
1081 /// The `no_mangle_const_items` lint detects any `const` items with the
1082 /// [`no_mangle` attribute].
1084 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1088 /// ```rust,compile_fail
1090 /// const FOO: i32 = 5;
1097 /// Constants do not have their symbols exported, and therefore, this
1098 /// probably means you meant to use a [`static`], not a [`const`].
1100 /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
1101 /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
1102 NO_MANGLE_CONST_ITEMS,
1104 "const items will not have their symbols exported"
1108 /// The `no_mangle_generic_items` lint detects generic items that must be
1115 /// fn foo<T>(t: T) {
1124 /// A function with generics must have its symbol mangled to accommodate
1125 /// the generic parameter. The [`no_mangle` attribute] has no effect in
1126 /// this situation, and should be removed.
1128 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1129 NO_MANGLE_GENERIC_ITEMS,
1131 "generic items must be mangled"
1134 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
1136 impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
1137 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1138 let attrs = cx.tcx.hir().attrs(it.hir_id());
1139 let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute,
1140 impl_generics: Option<&hir::Generics<'_>>,
1141 generics: &hir::Generics<'_>,
1144 generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1147 GenericParamKind::Lifetime { .. } => {}
1148 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1149 cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
1150 lint.build(fluent::lint::builtin_no_mangle_generic)
1151 .span_suggestion_short(
1152 no_mangle_attr.span,
1153 fluent::lint::suggestion,
1155 // Use of `#[no_mangle]` suggests FFI intent; correct
1156 // fix may be to monomorphize source by hand
1157 Applicability::MaybeIncorrect,
1167 hir::ItemKind::Fn(.., ref generics, _) => {
1168 if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
1169 check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
1172 hir::ItemKind::Const(..) => {
1173 if cx.sess().contains_name(attrs, sym::no_mangle) {
1174 // Const items do not refer to a particular location in memory, and therefore
1175 // don't have anything to attach a symbol to
1176 cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
1177 let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
1179 // account for "pub const" (#45562)
1184 .span_to_snippet(it.span)
1185 .map(|snippet| snippet.find("const").unwrap_or(0))
1186 .unwrap_or(0) as u32;
1187 // `const` is 5 chars
1188 let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1189 err.span_suggestion(
1191 fluent::lint::suggestion,
1193 Applicability::MachineApplicable,
1199 hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1201 if let hir::AssocItemKind::Fn { .. } = it.kind {
1202 if let Some(no_mangle_attr) = cx
1204 .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
1206 check_no_mangle_on_generic_fn(
1209 cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(),
1222 /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1223 /// T` because it is [undefined behavior].
1225 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1229 /// ```rust,compile_fail
1231 /// let y = std::mem::transmute::<&i32, &mut i32>(&5);
1239 /// Certain assumptions are made about aliasing of data, and this transmute
1240 /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1242 /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1245 "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1248 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1250 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1251 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1252 if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
1253 get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1255 if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
1256 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
1257 lint.build(fluent::lint::builtin_mutable_transmutes).emit();
1262 fn get_transmute_from_to<'tcx>(
1263 cx: &LateContext<'tcx>,
1264 expr: &hir::Expr<'_>,
1265 ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1266 let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1267 cx.qpath_res(qpath, expr.hir_id)
1271 if let Res::Def(DefKind::Fn, did) = def {
1272 if !def_id_is_transmute(cx, did) {
1275 let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1276 let from = sig.inputs().skip_binder()[0];
1277 let to = sig.output().skip_binder();
1278 return Some((from, to));
1283 fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1284 cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
1290 /// The `unstable_features` is deprecated and should no longer be used.
1293 "enabling unstable features (deprecated. do not use)"
1297 /// Forbids using the `#[feature(...)]` attribute
1298 UnstableFeatures => [UNSTABLE_FEATURES]
1301 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1302 fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
1303 if attr.has_name(sym::feature) {
1304 if let Some(items) = attr.meta_item_list() {
1306 cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
1307 lint.build(fluent::lint::builtin_unstable_features).emit();
1316 /// The `unreachable_pub` lint triggers for `pub` items not reachable from
1321 /// ```rust,compile_fail
1322 /// #![deny(unreachable_pub)]
1334 /// A bare `pub` visibility may be misleading if the item is not actually
1335 /// publicly exported from the crate. The `pub(crate)` visibility is
1336 /// recommended to be used instead, which more clearly expresses the intent
1337 /// that the item is only visible within its own crate.
1339 /// This lint is "allow" by default because it will trigger for a large
1340 /// amount existing Rust code, and has some false-positives. Eventually it
1341 /// is desired for this to become warn-by-default.
1342 pub UNREACHABLE_PUB,
1344 "`pub` items not reachable from crate root"
1348 /// Lint for items marked `pub` that aren't reachable from other crates.
1349 UnreachablePub => [UNREACHABLE_PUB]
1352 impl UnreachablePub {
1355 cx: &LateContext<'_>,
1361 let mut applicability = Applicability::MachineApplicable;
1362 if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
1363 if vis_span.from_expansion() {
1364 applicability = Applicability::MaybeIncorrect;
1366 let def_span = cx.tcx.def_span(def_id);
1367 cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
1368 let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
1369 err.set_arg("what", what);
1371 err.span_suggestion(
1373 fluent::lint::suggestion,
1378 err.help(fluent::lint::help);
1386 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1387 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1388 // Do not warn for fake `use` statements.
1389 if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1392 self.perform_lint(cx, "item", item.def_id.def_id, item.vis_span, true);
1395 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
1396 self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true);
1399 fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
1400 let def_id = cx.tcx.hir().local_def_id(field.hir_id);
1401 self.perform_lint(cx, "field", def_id, field.vis_span, false);
1404 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
1405 // Only lint inherent impl items.
1406 if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
1407 self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false);
1413 /// The `type_alias_bounds` lint detects bounds in type aliases.
1418 /// type SendVec<T: Send> = Vec<T>;
1425 /// The trait bounds in a type alias are currently ignored, and should not
1426 /// be included to avoid confusion. This was previously allowed
1427 /// unintentionally; this may become a hard error in the future.
1430 "bounds in type aliases are not enforced"
1434 /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1435 /// They are relevant when using associated types, but otherwise neither checked
1436 /// at definition site nor enforced at use site.
1437 TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1440 impl TypeAliasBounds {
1441 fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
1443 hir::QPath::TypeRelative(ref ty, _) => {
1444 // If this is a type variable, we found a `T::Assoc`.
1446 hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
1447 matches!(path.res, Res::Def(DefKind::TyParam, _))
1452 hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
1456 fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) {
1457 // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1458 // bound. Let's see if this type does that.
1460 // We use a HIR visitor to walk the type.
1461 use rustc_hir::intravisit::{self, Visitor};
1462 struct WalkAssocTypes<'a> {
1463 err: &'a mut Diagnostic,
1465 impl Visitor<'_> for WalkAssocTypes<'_> {
1466 fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
1467 if TypeAliasBounds::is_type_variable_assoc(qpath) {
1468 self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
1470 intravisit::walk_qpath(self, qpath, id)
1474 // Let's go for a walk!
1475 let mut visitor = WalkAssocTypes { err };
1476 visitor.visit_ty(ty);
1480 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1481 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1482 let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
1485 if let hir::TyKind::OpaqueDef(..) = ty.kind {
1486 // Bounds are respected for `type X = impl Trait`
1489 // There must not be a where clause
1490 if type_alias_generics.predicates.is_empty() {
1494 let mut where_spans = Vec::new();
1495 let mut inline_spans = Vec::new();
1496 let mut inline_sugg = Vec::new();
1497 for p in type_alias_generics.predicates {
1498 let span = p.span();
1499 if p.in_where_clause() {
1500 where_spans.push(span);
1502 for b in p.bounds() {
1503 inline_spans.push(b.span());
1505 inline_sugg.push((span, String::new()));
1509 let mut suggested_changing_assoc_types = false;
1510 if !where_spans.is_empty() {
1511 cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1512 let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
1513 err.set_span(where_spans);
1514 err.span_suggestion(
1515 type_alias_generics.where_clause_span,
1516 fluent::lint::suggestion,
1518 Applicability::MachineApplicable,
1520 if !suggested_changing_assoc_types {
1521 TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1522 suggested_changing_assoc_types = true;
1528 if !inline_spans.is_empty() {
1529 cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1530 let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
1531 err.set_span(inline_spans);
1532 err.multipart_suggestion(
1533 fluent::lint::suggestion,
1535 Applicability::MachineApplicable,
1537 if !suggested_changing_assoc_types {
1538 TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1547 /// Lint constants that are erroneous.
1548 /// Without this lint, we might not get any diagnostic if the constant is
1549 /// unused within this crate, even though downstream crates can't use it
1550 /// without producing an error.
1551 UnusedBrokenConst => []
1554 impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
1555 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1557 hir::ItemKind::Const(_, body_id) => {
1558 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1559 // trigger the query once for all constants since that will already report the errors
1560 cx.tcx.ensure().const_eval_poly(def_id);
1562 hir::ItemKind::Static(_, _, body_id) => {
1563 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1564 cx.tcx.ensure().eval_static_initializer(def_id);
1572 /// The `trivial_bounds` lint detects trait bounds that don't depend on
1573 /// any type parameters.
1578 /// #![feature(trivial_bounds)]
1579 /// pub struct A where i32: Copy;
1586 /// Usually you would not write a trait bound that you know is always
1587 /// true, or never true. However, when using macros, the macro may not
1588 /// know whether or not the constraint would hold or not at the time when
1589 /// generating the code. Currently, the compiler does not alert you if the
1590 /// constraint is always true, and generates an error if it is never true.
1591 /// The `trivial_bounds` feature changes this to be a warning in both
1592 /// cases, giving macros more freedom and flexibility to generate code,
1593 /// while still providing a signal when writing non-macro code that
1594 /// something is amiss.
1596 /// See [RFC 2056] for more details. This feature is currently only
1597 /// available on the nightly channel, see [tracking issue #48214].
1599 /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1600 /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1603 "these bounds don't depend on an type parameters"
1607 /// Lint for trait and lifetime bounds that don't depend on type parameters
1608 /// which either do nothing, or stop the item from being used.
1609 TrivialConstraints => [TRIVIAL_BOUNDS]
1612 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1613 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1614 use rustc_middle::ty::visit::TypeVisitable;
1615 use rustc_middle::ty::PredicateKind::*;
1617 if cx.tcx.features().trivial_bounds {
1618 let predicates = cx.tcx.predicates_of(item.def_id);
1619 for &(predicate, span) in predicates.predicates {
1620 let predicate_kind_name = match predicate.kind().skip_binder() {
1621 Trait(..) => "trait",
1623 RegionOutlives(..) => "lifetime",
1625 // Ignore projections, as they can only be global
1626 // if the trait bound is global
1628 // Ignore bounds that a user can't type
1634 ConstEvaluatable(..) |
1636 TypeWellFormedFromEnv(..) => continue,
1638 if predicate.is_global() {
1639 cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
1640 lint.build(fluent::lint::builtin_trivial_bounds)
1641 .set_arg("predicate_kind_name", predicate_kind_name)
1642 .set_arg("predicate", predicate)
1652 /// Does nothing as a lint pass, but registers some `Lint`s
1653 /// which are used by other parts of the compiler.
1657 NON_SHORTHAND_FIELD_PATTERNS,
1660 MISSING_COPY_IMPLEMENTATIONS,
1661 MISSING_DEBUG_IMPLEMENTATIONS,
1662 ANONYMOUS_PARAMETERS,
1663 UNUSED_DOC_COMMENTS,
1664 NO_MANGLE_CONST_ITEMS,
1665 NO_MANGLE_GENERIC_ITEMS,
1675 /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1676 /// pattern], which is deprecated.
1678 /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1682 /// ```rust,edition2018
1694 /// The `...` range pattern syntax was changed to `..=` to avoid potential
1695 /// confusion with the [`..` range expression]. Use the new form instead.
1697 /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1698 pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1700 "`...` range patterns are deprecated",
1701 @future_incompatible = FutureIncompatibleInfo {
1702 reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1703 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
1708 pub struct EllipsisInclusiveRangePatterns {
1709 /// If `Some(_)`, suppress all subsequent pattern
1710 /// warnings for better diagnostics.
1711 node_id: Option<ast::NodeId>,
1714 impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1716 impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1717 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1718 if self.node_id.is_some() {
1719 // Don't recursively warn about patterns inside range endpoints.
1723 use self::ast::{PatKind, RangeSyntax::DotDotDot};
1725 /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1726 /// corresponding to the ellipsis.
1727 fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1732 Spanned { span, node: RangeEnd::Included(DotDotDot) },
1733 ) => Some((a.as_deref(), b, *span)),
1738 let (parenthesise, endpoints) = match &pat.kind {
1739 PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
1740 _ => (false, matches_ellipsis_pat(pat)),
1743 if let Some((start, end, join)) = endpoints {
1744 let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
1745 let suggestion = fluent::lint::suggestion;
1747 self.node_id = Some(pat.id);
1748 let end = expr_to_string(&end);
1749 let replace = match start {
1750 Some(start) => format!("&({}..={})", expr_to_string(&start), end),
1751 None => format!("&(..={})", end),
1753 if join.edition() >= Edition::Edition2021 {
1754 cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1756 suggestion: pat.span,
1760 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
1766 Applicability::MachineApplicable,
1772 let replace = "..=";
1773 if join.edition() >= Edition::Edition2021 {
1774 cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1777 replace: replace.to_string(),
1780 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
1782 .span_suggestion_short(
1786 Applicability::MachineApplicable,
1795 fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1796 if let Some(node_id) = self.node_id {
1797 if pat.id == node_id {
1805 /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
1806 /// that are not able to be run by the test harness because they are in a
1807 /// position where they are not nameable.
1809 /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
1817 /// // This test will not fail because it does not run.
1818 /// assert_eq!(1, 2);
1827 /// In order for the test harness to run a test, the test function must be
1828 /// located in a position where it can be accessed from the crate root.
1829 /// This generally means it must be defined in a module, and not anywhere
1830 /// else such as inside another function. The compiler previously allowed
1831 /// this without an error, so a lint was added as an alert that a test is
1832 /// not being used. Whether or not this should be allowed has not yet been
1833 /// decided, see [RFC 2471] and [issue #36629].
1835 /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
1836 /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
1837 UNNAMEABLE_TEST_ITEMS,
1839 "detects an item that cannot be named being marked as `#[test_case]`",
1840 report_in_external_macro
1843 pub struct UnnameableTestItems {
1844 boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
1845 items_nameable: bool,
1848 impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1850 impl UnnameableTestItems {
1851 pub fn new() -> Self {
1852 Self { boundary: None, items_nameable: true }
1856 impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
1857 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1858 if self.items_nameable {
1859 if let hir::ItemKind::Mod(..) = it.kind {
1861 self.items_nameable = false;
1862 self.boundary = Some(it.def_id);
1867 let attrs = cx.tcx.hir().attrs(it.hir_id());
1868 if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
1869 cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
1870 lint.build(fluent::lint::builtin_unnameable_test_items).emit();
1875 fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
1876 if !self.items_nameable && self.boundary == Some(it.def_id) {
1877 self.items_nameable = true;
1883 /// The `keyword_idents` lint detects edition keywords being used as an
1888 /// ```rust,edition2015,compile_fail
1889 /// #![deny(keyword_idents)]
1898 /// Rust [editions] allow the language to evolve without breaking
1899 /// backwards compatibility. This lint catches code that uses new keywords
1900 /// that are added to the language that are used as identifiers (such as a
1901 /// variable name, function name, etc.). If you switch the compiler to a
1902 /// new edition without updating the code, then it will fail to compile if
1903 /// you are using a new keyword as an identifier.
1905 /// You can manually change the identifiers to a non-keyword, or use a
1906 /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1908 /// This lint solves the problem automatically. It is "allow" by default
1909 /// because the code is perfectly valid in older editions. The [`cargo
1910 /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1911 /// and automatically apply the suggested fix from the compiler (which is
1912 /// to use a raw identifier). This provides a completely automated way to
1913 /// update old code for a new edition.
1915 /// [editions]: https://doc.rust-lang.org/edition-guide/
1916 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1917 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1920 "detects edition keywords being used as an identifier",
1921 @future_incompatible = FutureIncompatibleInfo {
1922 reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1923 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
1928 /// Check for uses of edition keywords used as an identifier.
1929 KeywordIdents => [KEYWORD_IDENTS]
1932 struct UnderMacro(bool);
1934 impl KeywordIdents {
1935 fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
1936 for tt in tokens.into_trees() {
1938 // Only report non-raw idents.
1939 TokenTree::Token(token, _) => {
1940 if let Some((ident, false)) = token.ident() {
1941 self.check_ident_token(cx, UnderMacro(true), ident);
1944 TokenTree::Delimited(_, _, tts) => self.check_tokens(cx, tts),
1949 fn check_ident_token(
1951 cx: &EarlyContext<'_>,
1952 UnderMacro(under_macro): UnderMacro,
1955 let next_edition = match cx.sess().edition() {
1956 Edition::Edition2015 => {
1958 kw::Async | kw::Await | kw::Try => Edition::Edition2018,
1960 // rust-lang/rust#56327: Conservatively do not
1961 // attempt to report occurrences of `dyn` within
1962 // macro definitions or invocations, because `dyn`
1963 // can legitimately occur as a contextual keyword
1964 // in 2015 code denoting its 2018 meaning, and we
1965 // do not want rustfix to inject bugs into working
1966 // code by rewriting such occurrences.
1968 // But if we see `dyn` outside of a macro, we know
1969 // its precise role in the parsed AST and thus are
1970 // assured this is truly an attempt to use it as
1972 kw::Dyn if !under_macro => Edition::Edition2018,
1978 // There are no new keywords yet for the 2018 edition and beyond.
1982 // Don't lint `r#foo`.
1983 if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1987 cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
1988 lint.build(fluent::lint::builtin_keyword_idents)
1989 .set_arg("kw", ident.clone())
1990 .set_arg("next", next_edition)
1993 fluent::lint::suggestion,
1994 format!("r#{}", ident),
1995 Applicability::MachineApplicable,
2002 impl EarlyLintPass for KeywordIdents {
2003 fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
2004 self.check_tokens(cx, mac_def.body.inner_tokens());
2006 fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
2007 self.check_tokens(cx, mac.args.inner_tokens());
2009 fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
2010 self.check_ident_token(cx, UnderMacro(false), ident);
2014 declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
2016 impl ExplicitOutlivesRequirements {
2017 fn lifetimes_outliving_lifetime<'tcx>(
2018 inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2020 ) -> Vec<ty::Region<'tcx>> {
2023 .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2024 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
2025 ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
2033 fn lifetimes_outliving_type<'tcx>(
2034 inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2036 ) -> Vec<ty::Region<'tcx>> {
2039 .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2040 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
2041 a.is_param(index).then_some(b)
2048 fn collect_outlives_bound_spans<'tcx>(
2051 bounds: &hir::GenericBounds<'_>,
2052 inferred_outlives: &[ty::Region<'tcx>],
2053 ) -> Vec<(usize, Span)> {
2054 use rustc_middle::middle::resolve_lifetime::Region;
2059 .filter_map(|(i, bound)| {
2060 if let hir::GenericBound::Outlives(lifetime) = bound {
2061 let is_inferred = match tcx.named_region(lifetime.hir_id) {
2062 Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
2063 if let ty::ReEarlyBound(ebr) = **r {
2064 ebr.def_id == def_id
2071 is_inferred.then_some((i, bound.span()))
2076 .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
2080 fn consolidate_outlives_bound_spans(
2083 bounds: &hir::GenericBounds<'_>,
2084 bound_spans: Vec<(usize, Span)>,
2086 if bounds.is_empty() {
2089 if bound_spans.len() == bounds.len() {
2090 let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
2091 // If all bounds are inferable, we want to delete the colon, so
2092 // start from just after the parameter (span passed as argument)
2093 vec![lo.to(last_bound_span)]
2095 let mut merged = Vec::new();
2096 let mut last_merged_i = None;
2098 let mut from_start = true;
2099 for (i, bound_span) in bound_spans {
2100 match last_merged_i {
2101 // If the first bound is inferable, our span should also eat the leading `+`.
2103 merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2104 last_merged_i = Some(0);
2106 // If consecutive bounds are inferable, merge their spans
2107 Some(h) if i == h + 1 => {
2108 if let Some(tail) = merged.last_mut() {
2109 // Also eat the trailing `+` if the first
2110 // more-than-one bound is inferable
2111 let to_span = if from_start && i < bounds.len() {
2112 bounds[i + 1].span().shrink_to_lo()
2116 *tail = tail.to(to_span);
2117 last_merged_i = Some(i);
2119 bug!("another bound-span visited earlier");
2123 // When we find a non-inferable bound, subsequent inferable bounds
2124 // won't be consecutive from the start (and we'll eat the leading
2125 // `+` rather than the trailing one)
2127 merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
2128 last_merged_i = Some(i);
2137 impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2138 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
2139 use rustc_middle::middle::resolve_lifetime::Region;
2141 let def_id = item.def_id.def_id;
2142 if let hir::ItemKind::Struct(_, ref hir_generics)
2143 | hir::ItemKind::Enum(_, ref hir_generics)
2144 | hir::ItemKind::Union(_, ref hir_generics) = item.kind
2146 let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2147 if inferred_outlives.is_empty() {
2151 let ty_generics = cx.tcx.generics_of(def_id);
2153 let mut bound_count = 0;
2154 let mut lint_spans = Vec::new();
2155 let mut where_lint_spans = Vec::new();
2156 let mut dropped_predicate_count = 0;
2157 let num_predicates = hir_generics.predicates.len();
2158 for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
2159 let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
2160 hir::WherePredicate::RegionPredicate(predicate) => {
2161 if let Some(Region::EarlyBound(region_def_id)) =
2162 cx.tcx.named_region(predicate.lifetime.hir_id)
2165 Self::lifetimes_outliving_lifetime(
2171 predicate.in_where_clause,
2177 hir::WherePredicate::BoundPredicate(predicate) => {
2178 // FIXME we can also infer bounds on associated types,
2179 // and should check for them here.
2180 match predicate.bounded_ty.kind {
2181 hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2182 let Res::Def(DefKind::TyParam, def_id) = path.res else {
2185 let index = ty_generics.param_def_id_to_index[&def_id];
2187 Self::lifetimes_outliving_type(inferred_outlives, index),
2190 predicate.origin == PredicateOrigin::WhereClause,
2200 if relevant_lifetimes.is_empty() {
2205 self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
2206 bound_count += bound_spans.len();
2208 let drop_predicate = bound_spans.len() == bounds.len();
2210 dropped_predicate_count += 1;
2213 if drop_predicate && !in_where_clause {
2214 lint_spans.push(span);
2215 } else if drop_predicate && i + 1 < num_predicates {
2216 // If all the bounds on a predicate were inferable and there are
2217 // further predicates, we want to eat the trailing comma.
2218 let next_predicate_span = hir_generics.predicates[i + 1].span();
2219 where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
2221 where_lint_spans.extend(self.consolidate_outlives_bound_spans(
2222 span.shrink_to_lo(),
2229 // If all predicates are inferable, drop the entire clause
2230 // (including the `where`)
2231 if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
2233 let where_span = hir_generics.where_clause_span;
2234 // Extend the where clause back to the closing `>` of the
2235 // generics, except for tuple struct, which have the `where`
2236 // after the fields of the struct.
2237 let full_where_span =
2238 if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
2241 hir_generics.span.shrink_to_hi().to(where_span)
2243 lint_spans.push(full_where_span);
2245 lint_spans.extend(where_lint_spans);
2248 if !lint_spans.is_empty() {
2249 cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
2250 lint.build(fluent::lint::builtin_explicit_outlives)
2251 .set_arg("count", bound_count)
2252 .multipart_suggestion(
2253 fluent::lint::suggestion,
2256 .map(|span| (span, String::new()))
2257 .collect::<Vec<_>>(),
2258 Applicability::MachineApplicable,
2268 /// The `incomplete_features` lint detects unstable features enabled with
2269 /// the [`feature` attribute] that may function improperly in some or all
2272 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2277 /// #![feature(generic_const_exprs)]
2284 /// Although it is encouraged for people to experiment with unstable
2285 /// features, some of them are known to be incomplete or faulty. This lint
2286 /// is a signal that the feature has not yet been finished, and you may
2287 /// experience problems with it.
2288 pub INCOMPLETE_FEATURES,
2290 "incomplete features that may function improperly in some or all cases"
2294 /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
2295 IncompleteFeatures => [INCOMPLETE_FEATURES]
2298 impl EarlyLintPass for IncompleteFeatures {
2299 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
2300 let features = cx.sess().features_untracked();
2302 .declared_lang_features
2304 .map(|(name, span, _)| (name, span))
2305 .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
2306 .filter(|(&name, _)| features.incomplete(name))
2307 .for_each(|(&name, &span)| {
2308 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
2309 let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
2310 builder.set_arg("name", name);
2311 if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
2312 builder.set_arg("n", n);
2313 builder.note(fluent::lint::note);
2315 if HAS_MIN_FEATURES.contains(&name) {
2316 builder.help(fluent::lint::help);
2324 const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
2327 /// The `invalid_value` lint detects creating a value that is not valid,
2328 /// such as a null reference.
2333 /// # #![allow(unused)]
2335 /// let x: &'static i32 = std::mem::zeroed();
2343 /// In some situations the compiler can detect that the code is creating
2344 /// an invalid value, which should be avoided.
2346 /// In particular, this lint will check for improper use of
2347 /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2348 /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2349 /// lint should provide extra information to indicate what the problem is
2350 /// and a possible solution.
2352 /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2353 /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2354 /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2355 /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2356 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2359 "an invalid value is being created (such as a null reference)"
2362 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2364 impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2365 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2366 #[derive(Debug, Copy, Clone, PartialEq)]
2372 /// Information about why a type cannot be initialized this way.
2373 /// Contains an error message and optionally a span to point at.
2374 type InitError = (String, Option<Span>);
2376 /// Test if this constant is all-0.
2377 fn is_zero(expr: &hir::Expr<'_>) -> bool {
2378 use hir::ExprKind::*;
2379 use rustc_ast::LitKind::*;
2382 if let Int(i, _) = lit.node {
2388 Tup(tup) => tup.iter().all(is_zero),
2393 /// Determine if this expression is a "dangerous initialization".
2394 fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
2395 if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
2396 // Find calls to `mem::{uninitialized,zeroed}` methods.
2397 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2398 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2399 match cx.tcx.get_diagnostic_name(def_id) {
2400 Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2401 Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2402 Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2406 } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
2407 // Find problematic calls to `MaybeUninit::assume_init`.
2408 let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
2409 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2410 // This is a call to *some* method named `assume_init`.
2411 // See if the `self` parameter is one of the dangerous constructors.
2412 if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
2413 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2414 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2415 match cx.tcx.get_diagnostic_name(def_id) {
2416 Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2417 Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2428 /// Test if this enum has several actually "existing" variants.
2429 /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
2430 fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
2431 // As an approximation, we only count dataless variants. Those are definitely inhabited.
2432 let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
2433 existing_variants > 1
2436 /// Return `Some` only if we are sure this type does *not*
2437 /// allow zero initialization.
2438 fn ty_find_init_error<'tcx>(
2439 cx: &LateContext<'tcx>,
2442 ) -> Option<InitError> {
2443 use rustc_type_ir::sty::TyKind::*;
2445 // Primitive types that don't like 0 as a value.
2446 Ref(..) => Some(("references must be non-null".to_string(), None)),
2447 Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)),
2448 FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)),
2449 Never => Some(("the `!` type has no valid value".to_string(), None)),
2450 RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) =>
2451 // raw ptr to dyn Trait
2453 Some(("the vtable of a wide raw pointer must be non-null".to_string(), None))
2455 // Primitive types with other constraints.
2456 Bool if init == InitKind::Uninit => {
2457 Some(("booleans must be either `true` or `false`".to_string(), None))
2459 Char if init == InitKind::Uninit => {
2460 Some(("characters must be a valid Unicode codepoint".to_string(), None))
2462 Int(_) | Uint(_) if init == InitKind::Uninit => {
2463 Some(("integers must not be uninitialized".to_string(), None))
2465 Float(_) if init == InitKind::Uninit => {
2466 Some(("floats must not be uninitialized".to_string(), None))
2468 RawPtr(_) if init == InitKind::Uninit => {
2469 Some(("raw pointers must not be uninitialized".to_string(), None))
2471 // Recurse and checks for some compound types.
2472 Adt(adt_def, substs) if !adt_def.is_union() => {
2473 // First check if this ADT has a layout attribute (like `NonNull` and friends).
2474 use std::ops::Bound;
2475 match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
2476 // We exploit here that `layout_scalar_valid_range` will never
2477 // return `Bound::Excluded`. (And we have tests checking that we
2478 // handle the attribute correctly.)
2479 (Bound::Included(lo), _) if lo > 0 => {
2480 return Some((format!("`{}` must be non-null", ty), None));
2482 (Bound::Included(_), _) | (_, Bound::Included(_))
2483 if init == InitKind::Uninit =>
2487 "`{}` must be initialized inside its custom valid range",
2496 match adt_def.variants().len() {
2497 0 => Some(("enums with no variants have no valid value".to_string(), None)),
2499 // Struct, or enum with exactly one variant.
2500 // Proceed recursively, check all fields.
2501 let variant = &adt_def.variant(VariantIdx::from_u32(0));
2502 variant.fields.iter().find_map(|field| {
2503 ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
2506 // Point to this field, should be helpful for figuring
2507 // out where the source of the error is.
2508 let span = cx.tcx.def_span(field.did);
2511 " (in this {} field)",
2524 // Multi-variant enum.
2526 if init == InitKind::Uninit && is_multi_variant(*adt_def) {
2527 let span = cx.tcx.def_span(adt_def.did());
2529 "enums have to be initialized to a variant".to_string(),
2533 // In principle, for zero-initialization we could figure out which variant corresponds
2534 // to tag 0, and check that... but for now we just accept all zero-initializations.
2541 // Proceed recursively, check all fields.
2542 ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2545 if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
2546 // Array length known at array non-empty -- recurse.
2547 ty_find_init_error(cx, *ty, init)
2549 // Empty array or size unknown.
2553 // Conservative fallback.
2558 if let Some(init) = is_dangerous_init(cx, expr) {
2559 // This conjures an instance of a type out of nothing,
2560 // using zeroed or uninitialized memory.
2561 // We are extremely conservative with what we warn about.
2562 let conjured_ty = cx.typeck_results().expr_ty(expr);
2563 if let Some((msg, span)) =
2564 with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
2566 // FIXME(davidtwco): make translatable
2567 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
2568 let mut err = lint.build(&format!(
2569 "the type `{}` does not permit {}",
2572 InitKind::Zeroed => "zero-initialization",
2573 InitKind::Uninit => "being left uninitialized",
2576 err.span_label(expr.span, "this code causes undefined behavior when executed");
2579 "help: use `MaybeUninit<T>` instead, \
2580 and only call `assume_init` after initialization is done",
2582 if let Some(span) = span {
2583 err.span_note(span, &msg);
2595 /// The `clashing_extern_declarations` lint detects when an `extern fn`
2596 /// has been declared with the same name but different types.
2616 /// Because two symbols of the same name cannot be resolved to two
2617 /// different functions at link time, and one function cannot possibly
2618 /// have two types, a clashing extern declaration is almost certainly a
2619 /// mistake. Check to make sure that the `extern` definitions are correct
2620 /// and equivalent, and possibly consider unifying them in one location.
2622 /// This lint does not run between crates because a project may have
2623 /// dependencies which both rely on the same extern function, but declare
2624 /// it in a different (but valid) way. For example, they may both declare
2625 /// an opaque type for one or more of the arguments (which would end up
2626 /// distinct types), or use types that are valid conversions in the
2627 /// language the `extern fn` is defined in. In these cases, the compiler
2628 /// can't say that the clashing declaration is incorrect.
2629 pub CLASHING_EXTERN_DECLARATIONS,
2631 "detects when an extern fn has been declared with the same name but different types"
2634 pub struct ClashingExternDeclarations {
2635 /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
2636 /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
2637 /// the symbol should be reported as a clashing declaration.
2638 // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
2639 // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
2640 seen_decls: FxHashMap<Symbol, HirId>,
2643 /// Differentiate between whether the name for an extern decl came from the link_name attribute or
2644 /// just from declaration itself. This is important because we don't want to report clashes on
2645 /// symbol name if they don't actually clash because one or the other links against a symbol with a
2648 /// The name of the symbol + the span of the annotation which introduced the link name.
2650 /// No link name, so just the name of the symbol.
2655 fn get_name(&self) -> Symbol {
2657 SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
2662 impl ClashingExternDeclarations {
2663 pub(crate) fn new() -> Self {
2664 ClashingExternDeclarations { seen_decls: FxHashMap::default() }
2666 /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
2667 /// for the item, return its HirId without updating the set.
2668 fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
2669 let did = fi.def_id.to_def_id();
2670 let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
2671 let name = Symbol::intern(tcx.symbol_name(instance).name);
2672 if let Some(&hir_id) = self.seen_decls.get(&name) {
2673 // Avoid updating the map with the new entry when we do find a collision. We want to
2674 // make sure we're always pointing to the first definition as the previous declaration.
2675 // This lets us avoid emitting "knock-on" diagnostics.
2678 self.seen_decls.insert(name, fi.hir_id())
2682 /// Get the name of the symbol that's linked against for a given extern declaration. That is,
2683 /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
2685 fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
2686 if let Some((overridden_link_name, overridden_link_name_span)) =
2687 tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
2688 // FIXME: Instead of searching through the attributes again to get span
2689 // information, we could have codegen_fn_attrs also give span information back for
2690 // where the attribute was defined. However, until this is found to be a
2691 // bottleneck, this does just fine.
2693 overridden_link_name,
2694 tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
2698 SymbolName::Link(overridden_link_name, overridden_link_name_span)
2700 SymbolName::Normal(fi.ident.name)
2704 /// Checks whether two types are structurally the same enough that the declarations shouldn't
2705 /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
2706 /// with the same members (as the declarations shouldn't clash).
2707 fn structurally_same_type<'tcx>(
2708 cx: &LateContext<'tcx>,
2713 fn structurally_same_type_impl<'tcx>(
2714 seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
2715 cx: &LateContext<'tcx>,
2720 debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2723 // Given a transparent newtype, reach through and grab the inner
2724 // type unless the newtype makes the type non-null.
2725 let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
2728 if let ty::Adt(def, substs) = *ty.kind() {
2729 let is_transparent = def.repr().transparent();
2730 let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
2732 "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
2733 ty, is_transparent, is_non_null
2735 if is_transparent && !is_non_null {
2736 debug_assert!(def.variants().len() == 1);
2737 let v = &def.variant(VariantIdx::new(0));
2738 ty = transparent_newtype_field(tcx, v)
2740 "single-variant transparent structure with zero-sized field",
2746 debug!("non_transparent_ty -> {:?}", ty);
2751 let a = non_transparent_ty(a);
2752 let b = non_transparent_ty(b);
2754 if !seen_types.insert((a, b)) {
2755 // We've encountered a cycle. There's no point going any further -- the types are
2756 // structurally the same.
2761 // All nominally-same types are structurally same, too.
2764 // Do a full, depth-first comparison between the two.
2765 use rustc_type_ir::sty::TyKind::*;
2766 let a_kind = a.kind();
2767 let b_kind = b.kind();
2769 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
2770 debug!("compare_layouts({:?}, {:?})", a, b);
2771 let a_layout = &cx.layout_of(a)?.layout.abi();
2772 let b_layout = &cx.layout_of(b)?.layout.abi();
2774 "comparing layouts: {:?} == {:?} = {}",
2777 a_layout == b_layout
2779 Ok(a_layout == b_layout)
2782 #[allow(rustc::usage_of_ty_tykind)]
2783 let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
2784 kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
2787 ensure_sufficient_stack(|| {
2788 match (a_kind, b_kind) {
2789 (Adt(a_def, _), Adt(b_def, _)) => {
2790 // We can immediately rule out these types as structurally same if
2791 // their layouts differ.
2792 match compare_layouts(a, b) {
2793 Ok(false) => return false,
2794 _ => (), // otherwise, continue onto the full, fields comparison
2797 // Grab a flattened representation of all fields.
2798 let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
2799 let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
2801 // Perform a structural comparison for each field.
2804 |&ty::FieldDef { did: a_did, .. },
2805 &ty::FieldDef { did: b_did, .. }| {
2806 structurally_same_type_impl(
2816 (Array(a_ty, a_const), Array(b_ty, b_const)) => {
2817 // For arrays, we also check the constness of the type.
2818 a_const.kind() == b_const.kind()
2819 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2821 (Slice(a_ty), Slice(b_ty)) => {
2822 structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2824 (RawPtr(a_tymut), RawPtr(b_tymut)) => {
2825 a_tymut.mutbl == b_tymut.mutbl
2826 && structurally_same_type_impl(
2827 seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
2830 (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
2831 // For structural sameness, we don't need the region to be same.
2833 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2835 (FnDef(..), FnDef(..)) => {
2836 let a_poly_sig = a.fn_sig(tcx);
2837 let b_poly_sig = b.fn_sig(tcx);
2839 // We don't compare regions, but leaving bound regions around ICEs, so
2841 let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
2842 let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
2844 (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
2845 == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
2846 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2847 structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
2849 && structurally_same_type_impl(
2857 (Tuple(a_substs), Tuple(b_substs)) => {
2858 a_substs.iter().eq_by(b_substs.iter(), |a_ty, b_ty| {
2859 structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2862 // For these, it's not quite as easy to define structural-sameness quite so easily.
2863 // For the purposes of this lint, take the conservative approach and mark them as
2864 // not structurally same.
2865 (Dynamic(..), Dynamic(..))
2866 | (Error(..), Error(..))
2867 | (Closure(..), Closure(..))
2868 | (Generator(..), Generator(..))
2869 | (GeneratorWitness(..), GeneratorWitness(..))
2870 | (Projection(..), Projection(..))
2871 | (Opaque(..), Opaque(..)) => false,
2873 // These definitely should have been caught above.
2874 (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
2876 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
2877 // enum layout optimisation is being applied.
2878 (Adt(..), other_kind) | (other_kind, Adt(..))
2879 if is_primitive_or_pointer(other_kind) =>
2881 let (primitive, adt) =
2882 if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
2883 if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2886 compare_layouts(a, b).unwrap_or(false)
2889 // Otherwise, just compare the layouts. This may fail to lint for some
2890 // incompatible types, but at the very least, will stop reads into
2891 // uninitialised memory.
2892 _ => compare_layouts(a, b).unwrap_or(false),
2897 let mut seen_types = FxHashSet::default();
2898 structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
2902 impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
2904 impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
2905 fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
2906 trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
2907 if let ForeignItemKind::Fn(..) = this_fi.kind {
2909 if let Some(existing_hid) = self.insert(tcx, this_fi) {
2910 let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
2911 let this_decl_ty = tcx.type_of(this_fi.def_id);
2913 "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
2914 existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
2916 // Check that the declarations match.
2917 if !Self::structurally_same_type(
2921 CItemKind::Declaration,
2923 let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
2924 let orig = Self::name_of_extern_decl(tcx, orig_fi);
2926 // We want to ensure that we use spans for both decls that include where the
2927 // name was defined, whether that was from the link_name attribute or not.
2928 let get_relevant_span =
2929 |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
2930 SymbolName::Normal(_) => fi.span,
2931 SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
2933 // Finally, emit the diagnostic.
2934 tcx.struct_span_lint_hir(
2935 CLASHING_EXTERN_DECLARATIONS,
2937 get_relevant_span(this_fi),
2939 let mut expected_str = DiagnosticStyledString::new();
2940 expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
2941 let mut found_str = DiagnosticStyledString::new();
2942 found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
2944 lint.build(if orig.get_name() == this_fi.ident.name {
2945 fluent::lint::builtin_clashing_extern_same_name
2947 fluent::lint::builtin_clashing_extern_diff_name
2949 .set_arg("this_fi", this_fi.ident.name)
2950 .set_arg("orig", orig.get_name())
2952 get_relevant_span(orig_fi),
2953 fluent::lint::previous_decl_label,
2955 .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
2956 // FIXME(davidtwco): translatable expected/found
2957 .note_expected_found(&"", expected_str, &"", found_str)
2968 /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2969 /// which causes [undefined behavior].
2974 /// # #![allow(unused)]
2977 /// let x = &*ptr::null::<i32>();
2978 /// let x = ptr::addr_of!(*ptr::null::<i32>());
2979 /// let x = *(0 as *const i32);
2987 /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
2988 /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
2990 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2993 "detects when an null pointer is dereferenced"
2996 declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
2998 impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
2999 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
3000 /// test if expression is a null ptr
3001 fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
3003 rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
3004 if let rustc_hir::TyKind::Ptr(_) = ty.kind {
3005 return is_zero(expr) || is_null_ptr(cx, expr);
3008 // check for call to `core::ptr::null` or `core::ptr::null_mut`
3009 rustc_hir::ExprKind::Call(ref path, _) => {
3010 if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
3011 if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
3013 cx.tcx.get_diagnostic_name(def_id),
3014 Some(sym::ptr_null | sym::ptr_null_mut)
3024 /// test if expression is the literal `0`
3025 fn is_zero(expr: &hir::Expr<'_>) -> bool {
3027 rustc_hir::ExprKind::Lit(ref lit) => {
3028 if let LitKind::Int(a, _) = lit.node {
3037 if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
3038 if is_null_ptr(cx, expr_deref) {
3039 cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
3040 let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
3041 err.span_label(expr.span, fluent::lint::label);
3050 /// The `named_asm_labels` lint detects the use of named labels in the
3051 /// inline `asm!` macro.
3055 /// ```rust,compile_fail
3056 /// use std::arch::asm;
3060 /// asm!("foo: bar");
3069 /// LLVM is allowed to duplicate inline assembly blocks for any
3070 /// reason, for example when it is in a function that gets inlined. Because
3071 /// of this, GNU assembler [local labels] *must* be used instead of labels
3072 /// with a name. Using named labels might cause assembler or linker errors.
3074 /// See the explanation in [Rust By Example] for more details.
3076 /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
3077 /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
3078 pub NAMED_ASM_LABELS,
3080 "named labels in inline assembly",
3083 declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
3085 impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
3086 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
3088 kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
3092 for (template_sym, template_snippet, template_span) in template_strs.iter() {
3093 let template_str = template_sym.as_str();
3094 let find_label_span = |needle: &str| -> Option<Span> {
3095 if let Some(template_snippet) = template_snippet {
3096 let snippet = template_snippet.as_str();
3097 if let Some(pos) = snippet.find(needle) {
3101 .unwrap_or(snippet[pos..].len() - 1);
3102 let inner = InnerSpan::new(pos, end);
3103 return Some(template_span.from_inner(inner));
3110 let mut found_labels = Vec::new();
3112 // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
3113 let statements = template_str.split(|c| matches!(c, '\n' | ';'));
3114 for statement in statements {
3115 // If there's a comment, trim it from the statement
3116 let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
3117 let mut start_idx = 0;
3118 for (idx, _) in statement.match_indices(':') {
3119 let possible_label = statement[start_idx..idx].trim();
3120 let mut chars = possible_label.chars();
3121 let Some(c) = chars.next() else {
3122 // Empty string means a leading ':' in this section, which is not a label
3125 // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
3126 if (c.is_alphabetic() || matches!(c, '.' | '_'))
3127 && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
3129 found_labels.push(possible_label);
3131 // If we encounter a non-label, there cannot be any further labels, so stop checking
3135 start_idx = idx + 1;
3139 debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
3141 if found_labels.len() > 0 {
3142 let spans = found_labels
3144 .filter_map(|label| find_label_span(label))
3145 .collect::<Vec<Span>>();
3146 // If there were labels but we couldn't find a span, combine the warnings and use the template span
3147 let target_spans: MultiSpan =
3148 if spans.len() > 0 { spans.into() } else { (*template_span).into() };
3150 cx.lookup_with_diagnostics(
3154 diag.build(fluent::lint::builtin_asm_labels).emit();
3156 BuiltinLintDiagnostics::NamedAsmLabel(
3157 "only local labels of the form `<number>:` should be used in inline asm"
3168 /// The `special_module_name` lint detects module
3169 /// declarations for files that have a special meaning.
3173 /// ```rust,compile_fail
3185 /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
3186 /// library or binary crate, so declaring them as modules
3187 /// will lead to miscompilation of the crate unless configured
3190 /// To access a library from a binary target within the same crate,
3191 /// use `your_crate_name::` as the path path instead of `lib::`:
3193 /// ```rust,compile_fail
3194 /// // bar/src/lib.rs
3199 /// // bar/src/main.rs
3205 /// Binary targets cannot be used as libraries and so declaring
3206 /// one as a module is not allowed.
3207 pub SPECIAL_MODULE_NAME,
3209 "module declarations for files with a special meaning",
3212 declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
3214 impl EarlyLintPass for SpecialModuleName {
3215 fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
3216 for item in &krate.items {
3217 if let ast::ItemKind::Mod(
3219 ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
3222 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
3226 match item.ident.name.as_str() {
3227 "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3228 lint.build("found module declaration for lib.rs")
3229 .note("lib.rs is the root of this crate's library target")
3230 .help("to refer to it from other targets, use the library's name as the path")
3233 "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3234 lint.build("found module declaration for main.rs")
3235 .note("a binary crate cannot be used as library")
3245 pub use rustc_session::lint::builtin::UNEXPECTED_CFGS;
3247 declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]);
3249 impl EarlyLintPass for UnexpectedCfgs {
3250 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
3251 let cfg = &cx.sess().parse_sess.config;
3252 let check_cfg = &cx.sess().parse_sess.check_config;
3253 for &(name, value) in cfg {
3254 if let Some(names_valid) = &check_cfg.names_valid {
3255 if !names_valid.contains(&name) {
3256 cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
3257 diag.build(fluent::lint::builtin_unexpected_cli_config_name)
3258 .help(fluent::lint::help)
3259 .set_arg("name", name)
3264 if let Some(value) = value {
3265 if let Some(values) = &check_cfg.values_valid.get(&name) {
3266 if !values.contains(&value) {
3267 cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
3268 diag.build(fluent::lint::builtin_unexpected_cli_config_value)
3269 .help(fluent::lint::help)
3270 .set_arg("name", name)
3271 .set_arg("value", value)