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 binding = match binding_annot {
263 hir::BindingAnnotation::Unannotated => None,
264 hir::BindingAnnotation::Mutable => Some("mut"),
265 hir::BindingAnnotation::Ref => Some("ref"),
266 hir::BindingAnnotation::RefMut => Some("ref mut"),
268 let suggested_ident = if let Some(binding) = binding {
269 format!("{} {}", binding, ident)
273 lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
274 .set_arg("ident", ident.clone())
277 fluent::lint::suggestion,
279 Applicability::MachineApplicable,
291 /// The `unsafe_code` lint catches usage of `unsafe` code.
295 /// ```rust,compile_fail
296 /// #![deny(unsafe_code)]
308 /// This lint is intended to restrict the usage of `unsafe`, which can be
309 /// difficult to use correctly.
312 "usage of `unsafe` code"
315 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
320 cx: &EarlyContext<'_>,
322 decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
324 // This comes from a macro that has `#[allow_internal_unsafe]`.
325 if span.allows_unsafe() {
329 cx.struct_span_lint(UNSAFE_CODE, span, decorate);
332 fn report_overridden_symbol_name(
334 cx: &EarlyContext<'_>,
336 msg: DiagnosticMessage,
338 self.report_unsafe(cx, span, |lint| {
339 lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
343 fn report_overridden_symbol_section(
345 cx: &EarlyContext<'_>,
347 msg: DiagnosticMessage,
349 self.report_unsafe(cx, span, |lint| {
350 lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
355 impl EarlyLintPass for UnsafeCode {
356 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
357 if attr.has_name(sym::allow_internal_unsafe) {
358 self.report_unsafe(cx, attr.span, |lint| {
359 lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
364 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
365 if let ast::ExprKind::Block(ref blk, _) = e.kind {
366 // Don't warn about generated blocks; that'll just pollute the output.
367 if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
368 self.report_unsafe(cx, blk.span, |lint| {
369 lint.build(fluent::lint::builtin_unsafe_block).emit();
375 fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
377 ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
378 .report_unsafe(cx, it.span, |lint| {
379 lint.build(fluent::lint::builtin_unsafe_trait).emit();
382 ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
383 .report_unsafe(cx, it.span, |lint| {
384 lint.build(fluent::lint::builtin_unsafe_impl).emit();
387 ast::ItemKind::Fn(..) => {
388 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
389 self.report_overridden_symbol_name(
392 fluent::lint::builtin_no_mangle_fn,
396 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
397 self.report_overridden_symbol_name(
400 fluent::lint::builtin_export_name_fn,
404 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
405 self.report_overridden_symbol_section(
408 fluent::lint::builtin_link_section_fn,
413 ast::ItemKind::Static(..) => {
414 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
415 self.report_overridden_symbol_name(
418 fluent::lint::builtin_no_mangle_static,
422 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
423 self.report_overridden_symbol_name(
426 fluent::lint::builtin_export_name_static,
430 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
431 self.report_overridden_symbol_section(
434 fluent::lint::builtin_link_section_static,
443 fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
444 if let ast::AssocItemKind::Fn(..) = it.kind {
445 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
446 self.report_overridden_symbol_name(
449 fluent::lint::builtin_no_mangle_method,
452 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
453 self.report_overridden_symbol_name(
456 fluent::lint::builtin_export_name_method,
462 fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
466 ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
472 let msg = match ctxt {
473 FnCtxt::Foreign => return,
474 FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
475 FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
476 FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
478 self.report_unsafe(cx, span, |lint| {
479 lint.build(msg).emit();
486 /// The `missing_docs` lint detects missing documentation for public items.
490 /// ```rust,compile_fail
491 /// #![deny(missing_docs)]
499 /// This lint is intended to ensure that a library is well-documented.
500 /// Items without documentation can be difficult for users to understand
501 /// how to use properly.
503 /// This lint is "allow" by default because it can be noisy, and not all
504 /// projects may want to enforce everything to be documented.
507 "detects missing documentation for public members",
508 report_in_external_macro
511 pub struct MissingDoc {
512 /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
513 doc_hidden_stack: Vec<bool>,
516 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
518 fn has_doc(attr: &ast::Attribute) -> bool {
519 if attr.is_doc_comment() {
523 if !attr.has_name(sym::doc) {
527 if attr.value_str().is_some() {
531 if let Some(list) = attr.meta_item_list() {
533 if meta.has_name(sym::hidden) {
543 pub fn new() -> MissingDoc {
544 MissingDoc { doc_hidden_stack: vec![false] }
547 fn doc_hidden(&self) -> bool {
548 *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
551 fn check_missing_docs_attrs(
553 cx: &LateContext<'_>,
555 article: &'static str,
558 // If we're building a test harness, then warning about
559 // documentation is probably not really relevant right now.
560 if cx.sess().opts.test {
564 // `#[doc(hidden)]` disables missing_docs check.
565 if self.doc_hidden() {
569 // Only check publicly-visible items, using the result from the privacy pass.
570 // It's an option so the crate root can also use this function (it doesn't
572 if def_id != CRATE_DEF_ID {
573 if !cx.access_levels.is_exported(def_id) {
578 let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
579 let has_doc = attrs.iter().any(has_doc);
581 cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
582 lint.build(fluent::lint::builtin_missing_doc)
583 .set_arg("article", article)
584 .set_arg("desc", desc)
591 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
592 fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
593 let doc_hidden = self.doc_hidden()
594 || attrs.iter().any(|attr| {
595 attr.has_name(sym::doc)
596 && match attr.meta_item_list() {
598 Some(l) => attr::list_contains_name(&l, sym::hidden),
601 self.doc_hidden_stack.push(doc_hidden);
604 fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
605 self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
608 fn check_crate(&mut self, cx: &LateContext<'_>) {
609 self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
612 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
614 hir::ItemKind::Trait(..) => {
615 // Issue #11592: traits are always considered exported, even when private.
616 if cx.tcx.visibility(it.def_id)
617 == ty::Visibility::Restricted(
618 cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
624 hir::ItemKind::TyAlias(..)
625 | hir::ItemKind::Fn(..)
626 | hir::ItemKind::Macro(..)
627 | hir::ItemKind::Mod(..)
628 | hir::ItemKind::Enum(..)
629 | hir::ItemKind::Struct(..)
630 | hir::ItemKind::Union(..)
631 | hir::ItemKind::Const(..)
632 | hir::ItemKind::Static(..) => {}
637 let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
639 self.check_missing_docs_attrs(cx, it.def_id, article, desc);
642 fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
643 let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
645 self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc);
648 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
649 // If the method is an impl for a trait, don't doc.
650 if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl {
654 // If the method is an impl for an item with docs_hidden, don't doc.
655 if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
656 let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
657 let impl_ty = cx.tcx.type_of(parent);
658 let outerdef = match impl_ty.kind() {
659 ty::Adt(def, _) => Some(def.did()),
660 ty::Foreign(def_id) => Some(*def_id),
663 let is_hidden = match outerdef {
664 Some(id) => cx.tcx.is_doc_hidden(id),
672 let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
673 self.check_missing_docs_attrs(cx, impl_item.def_id, article, desc);
676 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
677 let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
678 self.check_missing_docs_attrs(cx, foreign_item.def_id, article, desc);
681 fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
682 if !sf.is_positional() {
683 let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
684 self.check_missing_docs_attrs(cx, def_id, "a", "struct field")
688 fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
689 self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), "a", "variant");
694 /// The `missing_copy_implementations` lint detects potentially-forgotten
695 /// implementations of [`Copy`].
697 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
701 /// ```rust,compile_fail
702 /// #![deny(missing_copy_implementations)]
713 /// Historically (before 1.0), types were automatically marked as `Copy`
714 /// if possible. This was changed so that it required an explicit opt-in
715 /// by implementing the `Copy` trait. As part of this change, a lint was
716 /// added to alert if a copyable type was not marked `Copy`.
718 /// This lint is "allow" by default because this code isn't bad; it is
719 /// common to write newtypes like this specifically so that a `Copy` type
720 /// is no longer `Copy`. `Copy` types can result in unintended copies of
721 /// large data which can impact performance.
722 pub MISSING_COPY_IMPLEMENTATIONS,
724 "detects potentially-forgotten implementations of `Copy`"
727 declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
729 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
730 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
731 if !cx.access_levels.is_reachable(item.def_id) {
734 let (def, ty) = match item.kind {
735 hir::ItemKind::Struct(_, ref ast_generics) => {
736 if !ast_generics.params.is_empty() {
739 let def = cx.tcx.adt_def(item.def_id);
740 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
742 hir::ItemKind::Union(_, ref ast_generics) => {
743 if !ast_generics.params.is_empty() {
746 let def = cx.tcx.adt_def(item.def_id);
747 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
749 hir::ItemKind::Enum(_, ref ast_generics) => {
750 if !ast_generics.params.is_empty() {
753 let def = cx.tcx.adt_def(item.def_id);
754 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
758 if def.has_dtor(cx.tcx) {
761 let param_env = ty::ParamEnv::empty();
762 if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
765 if can_type_implement_copy(
769 traits::ObligationCause::misc(item.span, item.hir_id()),
773 cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
774 lint.build(fluent::lint::builtin_missing_copy_impl).emit();
781 /// The `missing_debug_implementations` lint detects missing
782 /// implementations of [`fmt::Debug`].
784 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
788 /// ```rust,compile_fail
789 /// #![deny(missing_debug_implementations)]
798 /// Having a `Debug` implementation on all types can assist with
799 /// debugging, as it provides a convenient way to format and display a
800 /// value. Using the `#[derive(Debug)]` attribute will automatically
801 /// generate a typical implementation, or a custom implementation can be
802 /// added by manually implementing the `Debug` trait.
804 /// This lint is "allow" by default because adding `Debug` to all types can
805 /// have a negative impact on compile time and code size. It also requires
806 /// boilerplate to be added to every type, which can be an impediment.
807 MISSING_DEBUG_IMPLEMENTATIONS,
809 "detects missing implementations of Debug"
813 pub struct MissingDebugImplementations {
814 impling_types: Option<LocalDefIdSet>,
817 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
819 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
820 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
821 if !cx.access_levels.is_reachable(item.def_id) {
826 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
830 let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
834 if self.impling_types.is_none() {
835 let mut impls = LocalDefIdSet::default();
836 cx.tcx.for_each_impl(debug, |d| {
837 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
838 if let Some(def_id) = ty_def.did().as_local() {
839 impls.insert(def_id);
844 self.impling_types = Some(impls);
845 debug!("{:?}", self.impling_types);
848 if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
849 cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
850 lint.build(fluent::lint::builtin_missing_debug_impl)
851 .set_arg("debug", cx.tcx.def_path_str(debug))
859 /// The `anonymous_parameters` lint detects anonymous parameters in trait
864 /// ```rust,edition2015,compile_fail
865 /// #![deny(anonymous_parameters)]
877 /// This syntax is mostly a historical accident, and can be worked around
878 /// quite easily by adding an `_` pattern or a descriptive identifier:
882 /// fn foo(_: usize);
886 /// This syntax is now a hard error in the 2018 edition. In the 2015
887 /// edition, this lint is "warn" by default. This lint
888 /// enables the [`cargo fix`] tool with the `--edition` flag to
889 /// automatically transition old code from the 2015 edition to 2018. The
890 /// tool will run this lint and automatically apply the
891 /// suggested fix from the compiler (which is to add `_` to each
892 /// parameter). This provides a completely automated way to update old
893 /// code for a new edition. See [issue #41686] for more details.
895 /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
896 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
897 pub ANONYMOUS_PARAMETERS,
899 "detects anonymous parameters",
900 @future_incompatible = FutureIncompatibleInfo {
901 reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
902 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
907 /// Checks for use of anonymous parameters (RFC 1685).
908 AnonymousParameters => [ANONYMOUS_PARAMETERS]
911 impl EarlyLintPass for AnonymousParameters {
912 fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
913 if cx.sess().edition() != Edition::Edition2015 {
914 // This is a hard error in future editions; avoid linting and erroring
917 if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
918 for arg in sig.decl.inputs.iter() {
919 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
920 if ident.name == kw::Empty {
921 cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
922 let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
924 let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
925 (snip.as_str(), Applicability::MachineApplicable)
927 ("<type>", Applicability::HasPlaceholders)
930 lint.build(fluent::lint::builtin_anonymous_params)
933 fluent::lint::suggestion,
934 format!("_: {}", ty_snip),
946 /// Check for use of attributes which have been deprecated.
948 pub struct DeprecatedAttr {
949 // This is not free to compute, so we want to keep it around, rather than
950 // compute it for every attribute.
951 depr_attrs: Vec<&'static BuiltinAttribute>,
954 impl_lint_pass!(DeprecatedAttr => []);
956 impl DeprecatedAttr {
957 pub fn new() -> DeprecatedAttr {
958 DeprecatedAttr { depr_attrs: deprecated_attributes() }
962 impl EarlyLintPass for DeprecatedAttr {
963 fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
964 for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
965 if attr.ident().map(|ident| ident.name) == Some(*name) {
966 if let &AttributeGate::Gated(
967 Stability::Deprecated(link, suggestion),
973 cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
974 // FIXME(davidtwco) translatable deprecated attr
975 lint.build(fluent::lint::builtin_deprecated_attr_link)
976 .set_arg("name", name)
977 .set_arg("reason", reason)
978 .set_arg("link", link)
979 .span_suggestion_short(
981 suggestion.map(|s| s.into()).unwrap_or(
982 fluent::lint::builtin_deprecated_attr_default_suggestion,
985 Applicability::MachineApplicable,
993 if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
994 cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
995 lint.build(fluent::lint::builtin_deprecated_attr_used)
996 .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
997 .span_suggestion_short(
999 fluent::lint::builtin_deprecated_attr_default_suggestion,
1001 Applicability::MachineApplicable,
1009 fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
1010 use rustc_ast::token::CommentKind;
1012 let mut attrs = attrs.iter().peekable();
1014 // Accumulate a single span for sugared doc comments.
1015 let mut sugared_span: Option<Span> = None;
1017 while let Some(attr) = attrs.next() {
1018 let is_doc_comment = attr.is_doc_comment();
1021 Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
1024 if attrs.peek().map_or(false, |next_attr| next_attr.is_doc_comment()) {
1028 let span = sugared_span.take().unwrap_or(attr.span);
1030 if is_doc_comment || attr.has_name(sym::doc) {
1031 cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
1032 let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
1033 err.set_arg("kind", node_kind);
1034 err.span_label(node_span, fluent::lint::label);
1036 AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
1037 err.help(fluent::lint::plain_help);
1039 AttrKind::DocComment(CommentKind::Block, _) => {
1040 err.help(fluent::lint::block_help);
1049 impl EarlyLintPass for UnusedDocComment {
1050 fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
1051 let kind = match stmt.kind {
1052 ast::StmtKind::Local(..) => "statements",
1053 // Disabled pending discussion in #78306
1054 ast::StmtKind::Item(..) => return,
1055 // expressions will be reported by `check_expr`.
1056 ast::StmtKind::Empty
1057 | ast::StmtKind::Semi(_)
1058 | ast::StmtKind::Expr(_)
1059 | ast::StmtKind::MacCall(_) => return,
1062 warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
1065 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1066 let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
1067 warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1070 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1071 warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
1074 fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
1075 warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs);
1078 fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
1079 warn_if_doc(cx, block.span, "blocks", &block.attrs());
1082 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1083 if let ast::ItemKind::ForeignMod(_) = item.kind {
1084 warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
1090 /// The `no_mangle_const_items` lint detects any `const` items with the
1091 /// [`no_mangle` attribute].
1093 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1097 /// ```rust,compile_fail
1099 /// const FOO: i32 = 5;
1106 /// Constants do not have their symbols exported, and therefore, this
1107 /// probably means you meant to use a [`static`], not a [`const`].
1109 /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
1110 /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
1111 NO_MANGLE_CONST_ITEMS,
1113 "const items will not have their symbols exported"
1117 /// The `no_mangle_generic_items` lint detects generic items that must be
1124 /// fn foo<T>(t: T) {
1133 /// A function with generics must have its symbol mangled to accommodate
1134 /// the generic parameter. The [`no_mangle` attribute] has no effect in
1135 /// this situation, and should be removed.
1137 /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
1138 NO_MANGLE_GENERIC_ITEMS,
1140 "generic items must be mangled"
1143 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
1145 impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
1146 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1147 let attrs = cx.tcx.hir().attrs(it.hir_id());
1148 let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute,
1149 impl_generics: Option<&hir::Generics<'_>>,
1150 generics: &hir::Generics<'_>,
1153 generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
1156 GenericParamKind::Lifetime { .. } => {}
1157 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1158 cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
1159 lint.build(fluent::lint::builtin_no_mangle_generic)
1160 .span_suggestion_short(
1161 no_mangle_attr.span,
1162 fluent::lint::suggestion,
1164 // Use of `#[no_mangle]` suggests FFI intent; correct
1165 // fix may be to monomorphize source by hand
1166 Applicability::MaybeIncorrect,
1176 hir::ItemKind::Fn(.., ref generics, _) => {
1177 if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
1178 check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
1181 hir::ItemKind::Const(..) => {
1182 if cx.sess().contains_name(attrs, sym::no_mangle) {
1183 // Const items do not refer to a particular location in memory, and therefore
1184 // don't have anything to attach a symbol to
1185 cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
1186 let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
1188 // account for "pub const" (#45562)
1193 .span_to_snippet(it.span)
1194 .map(|snippet| snippet.find("const").unwrap_or(0))
1195 .unwrap_or(0) as u32;
1196 // `const` is 5 chars
1197 let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
1198 err.span_suggestion(
1200 fluent::lint::suggestion,
1202 Applicability::MachineApplicable,
1208 hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
1210 if let hir::AssocItemKind::Fn { .. } = it.kind {
1211 if let Some(no_mangle_attr) = cx
1213 .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
1215 check_no_mangle_on_generic_fn(
1218 cx.tcx.hir().get_generics(it.id.def_id).unwrap(),
1231 /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1232 /// T` because it is [undefined behavior].
1234 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1238 /// ```rust,compile_fail
1240 /// let y = std::mem::transmute::<&i32, &mut i32>(&5);
1248 /// Certain assumptions are made about aliasing of data, and this transmute
1249 /// violates those assumptions. Consider using [`UnsafeCell`] instead.
1251 /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1254 "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1257 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1259 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1260 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1261 if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
1262 get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1264 if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
1265 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
1266 lint.build(fluent::lint::builtin_mutable_transmutes).emit();
1271 fn get_transmute_from_to<'tcx>(
1272 cx: &LateContext<'tcx>,
1273 expr: &hir::Expr<'_>,
1274 ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1275 let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1276 cx.qpath_res(qpath, expr.hir_id)
1280 if let Res::Def(DefKind::Fn, did) = def {
1281 if !def_id_is_transmute(cx, did) {
1284 let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1285 let from = sig.inputs().skip_binder()[0];
1286 let to = sig.output().skip_binder();
1287 return Some((from, to));
1292 fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1293 cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
1299 /// The `unstable_features` is deprecated and should no longer be used.
1302 "enabling unstable features (deprecated. do not use)"
1306 /// Forbids using the `#[feature(...)]` attribute
1307 UnstableFeatures => [UNSTABLE_FEATURES]
1310 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1311 fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
1312 if attr.has_name(sym::feature) {
1313 if let Some(items) = attr.meta_item_list() {
1315 cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
1316 lint.build(fluent::lint::builtin_unstable_features).emit();
1325 /// The `unreachable_pub` lint triggers for `pub` items not reachable from
1330 /// ```rust,compile_fail
1331 /// #![deny(unreachable_pub)]
1343 /// A bare `pub` visibility may be misleading if the item is not actually
1344 /// publicly exported from the crate. The `pub(crate)` visibility is
1345 /// recommended to be used instead, which more clearly expresses the intent
1346 /// that the item is only visible within its own crate.
1348 /// This lint is "allow" by default because it will trigger for a large
1349 /// amount existing Rust code, and has some false-positives. Eventually it
1350 /// is desired for this to become warn-by-default.
1351 pub UNREACHABLE_PUB,
1353 "`pub` items not reachable from crate root"
1357 /// Lint for items marked `pub` that aren't reachable from other crates.
1358 UnreachablePub => [UNREACHABLE_PUB]
1361 impl UnreachablePub {
1364 cx: &LateContext<'_>,
1370 let mut applicability = Applicability::MachineApplicable;
1371 if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
1372 if vis_span.from_expansion() {
1373 applicability = Applicability::MaybeIncorrect;
1375 let def_span = cx.tcx.def_span(def_id);
1376 cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
1377 let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
1378 err.set_arg("what", what);
1380 err.span_suggestion(
1382 fluent::lint::suggestion,
1387 err.help(fluent::lint::help);
1395 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
1396 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1397 // Do not warn for fake `use` statements.
1398 if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
1401 self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
1404 fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
1405 self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
1408 fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
1409 let def_id = cx.tcx.hir().local_def_id(field.hir_id);
1410 self.perform_lint(cx, "field", def_id, field.vis_span, false);
1413 fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
1414 // Only lint inherent impl items.
1415 if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
1416 self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
1422 /// The `type_alias_bounds` lint detects bounds in type aliases.
1427 /// type SendVec<T: Send> = Vec<T>;
1434 /// The trait bounds in a type alias are currently ignored, and should not
1435 /// be included to avoid confusion. This was previously allowed
1436 /// unintentionally; this may become a hard error in the future.
1439 "bounds in type aliases are not enforced"
1443 /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1444 /// They are relevant when using associated types, but otherwise neither checked
1445 /// at definition site nor enforced at use site.
1446 TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1449 impl TypeAliasBounds {
1450 fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
1452 hir::QPath::TypeRelative(ref ty, _) => {
1453 // If this is a type variable, we found a `T::Assoc`.
1455 hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
1456 matches!(path.res, Res::Def(DefKind::TyParam, _))
1461 hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
1465 fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) {
1466 // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1467 // bound. Let's see if this type does that.
1469 // We use a HIR visitor to walk the type.
1470 use rustc_hir::intravisit::{self, Visitor};
1471 struct WalkAssocTypes<'a> {
1472 err: &'a mut Diagnostic,
1474 impl Visitor<'_> for WalkAssocTypes<'_> {
1475 fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
1476 if TypeAliasBounds::is_type_variable_assoc(qpath) {
1477 self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
1479 intravisit::walk_qpath(self, qpath, id, span)
1483 // Let's go for a walk!
1484 let mut visitor = WalkAssocTypes { err };
1485 visitor.visit_ty(ty);
1489 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
1490 fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
1491 let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
1494 if let hir::TyKind::OpaqueDef(..) = ty.kind {
1495 // Bounds are respected for `type X = impl Trait`
1498 // There must not be a where clause
1499 if type_alias_generics.predicates.is_empty() {
1503 let mut where_spans = Vec::new();
1504 let mut inline_spans = Vec::new();
1505 let mut inline_sugg = Vec::new();
1506 for p in type_alias_generics.predicates {
1507 let span = p.span();
1508 if p.in_where_clause() {
1509 where_spans.push(span);
1511 for b in p.bounds() {
1512 inline_spans.push(b.span());
1514 inline_sugg.push((span, String::new()));
1518 let mut suggested_changing_assoc_types = false;
1519 if !where_spans.is_empty() {
1520 cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1521 let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
1522 err.set_span(where_spans);
1523 err.span_suggestion(
1524 type_alias_generics.where_clause_span,
1525 fluent::lint::suggestion,
1527 Applicability::MachineApplicable,
1529 if !suggested_changing_assoc_types {
1530 TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1531 suggested_changing_assoc_types = true;
1537 if !inline_spans.is_empty() {
1538 cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
1539 let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
1540 err.set_span(inline_spans);
1541 err.multipart_suggestion(
1542 fluent::lint::suggestion,
1544 Applicability::MachineApplicable,
1546 if !suggested_changing_assoc_types {
1547 TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1556 /// Lint constants that are erroneous.
1557 /// Without this lint, we might not get any diagnostic if the constant is
1558 /// unused within this crate, even though downstream crates can't use it
1559 /// without producing an error.
1560 UnusedBrokenConst => []
1563 impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
1564 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1566 hir::ItemKind::Const(_, body_id) => {
1567 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1568 // trigger the query once for all constants since that will already report the errors
1569 cx.tcx.ensure().const_eval_poly(def_id);
1571 hir::ItemKind::Static(_, _, body_id) => {
1572 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
1573 cx.tcx.ensure().eval_static_initializer(def_id);
1581 /// The `trivial_bounds` lint detects trait bounds that don't depend on
1582 /// any type parameters.
1587 /// #![feature(trivial_bounds)]
1588 /// pub struct A where i32: Copy;
1595 /// Usually you would not write a trait bound that you know is always
1596 /// true, or never true. However, when using macros, the macro may not
1597 /// know whether or not the constraint would hold or not at the time when
1598 /// generating the code. Currently, the compiler does not alert you if the
1599 /// constraint is always true, and generates an error if it is never true.
1600 /// The `trivial_bounds` feature changes this to be a warning in both
1601 /// cases, giving macros more freedom and flexibility to generate code,
1602 /// while still providing a signal when writing non-macro code that
1603 /// something is amiss.
1605 /// See [RFC 2056] for more details. This feature is currently only
1606 /// available on the nightly channel, see [tracking issue #48214].
1608 /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
1609 /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
1612 "these bounds don't depend on an type parameters"
1616 /// Lint for trait and lifetime bounds that don't depend on type parameters
1617 /// which either do nothing, or stop the item from being used.
1618 TrivialConstraints => [TRIVIAL_BOUNDS]
1621 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1622 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1623 use rustc_middle::ty::visit::TypeVisitable;
1624 use rustc_middle::ty::PredicateKind::*;
1626 if cx.tcx.features().trivial_bounds {
1627 let predicates = cx.tcx.predicates_of(item.def_id);
1628 for &(predicate, span) in predicates.predicates {
1629 let predicate_kind_name = match predicate.kind().skip_binder() {
1630 Trait(..) => "trait",
1632 RegionOutlives(..) => "lifetime",
1634 // Ignore projections, as they can only be global
1635 // if the trait bound is global
1637 // Ignore bounds that a user can't type
1643 ConstEvaluatable(..) |
1645 TypeWellFormedFromEnv(..) => continue,
1647 if predicate.is_global() {
1648 cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
1649 lint.build(fluent::lint::builtin_trivial_bounds)
1650 .set_arg("predicate_kind_name", predicate_kind_name)
1651 .set_arg("predicate", predicate)
1661 /// Does nothing as a lint pass, but registers some `Lint`s
1662 /// which are used by other parts of the compiler.
1666 NON_SHORTHAND_FIELD_PATTERNS,
1669 MISSING_COPY_IMPLEMENTATIONS,
1670 MISSING_DEBUG_IMPLEMENTATIONS,
1671 ANONYMOUS_PARAMETERS,
1672 UNUSED_DOC_COMMENTS,
1673 NO_MANGLE_CONST_ITEMS,
1674 NO_MANGLE_GENERIC_ITEMS,
1684 /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
1685 /// pattern], which is deprecated.
1687 /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
1691 /// ```rust,edition2018
1703 /// The `...` range pattern syntax was changed to `..=` to avoid potential
1704 /// confusion with the [`..` range expression]. Use the new form instead.
1706 /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
1707 pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1709 "`...` range patterns are deprecated",
1710 @future_incompatible = FutureIncompatibleInfo {
1711 reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
1712 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
1717 pub struct EllipsisInclusiveRangePatterns {
1718 /// If `Some(_)`, suppress all subsequent pattern
1719 /// warnings for better diagnostics.
1720 node_id: Option<ast::NodeId>,
1723 impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1725 impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1726 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1727 if self.node_id.is_some() {
1728 // Don't recursively warn about patterns inside range endpoints.
1732 use self::ast::{PatKind, RangeSyntax::DotDotDot};
1734 /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1735 /// corresponding to the ellipsis.
1736 fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
1741 Spanned { span, node: RangeEnd::Included(DotDotDot) },
1742 ) => Some((a.as_deref(), b, *span)),
1747 let (parenthesise, endpoints) = match &pat.kind {
1748 PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
1749 _ => (false, matches_ellipsis_pat(pat)),
1752 if let Some((start, end, join)) = endpoints {
1753 let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
1754 let suggestion = fluent::lint::suggestion;
1756 self.node_id = Some(pat.id);
1757 let end = expr_to_string(&end);
1758 let replace = match start {
1759 Some(start) => format!("&({}..={})", expr_to_string(&start), end),
1760 None => format!("&(..={})", end),
1762 if join.edition() >= Edition::Edition2021 {
1763 cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1765 suggestion: pat.span,
1769 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
1775 Applicability::MachineApplicable,
1781 let replace = "..=";
1782 if join.edition() >= Edition::Edition2021 {
1783 cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
1786 replace: replace.to_string(),
1789 cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
1791 .span_suggestion_short(
1795 Applicability::MachineApplicable,
1804 fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1805 if let Some(node_id) = self.node_id {
1806 if pat.id == node_id {
1814 /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
1815 /// that are not able to be run by the test harness because they are in a
1816 /// position where they are not nameable.
1818 /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
1826 /// // This test will not fail because it does not run.
1827 /// assert_eq!(1, 2);
1836 /// In order for the test harness to run a test, the test function must be
1837 /// located in a position where it can be accessed from the crate root.
1838 /// This generally means it must be defined in a module, and not anywhere
1839 /// else such as inside another function. The compiler previously allowed
1840 /// this without an error, so a lint was added as an alert that a test is
1841 /// not being used. Whether or not this should be allowed has not yet been
1842 /// decided, see [RFC 2471] and [issue #36629].
1844 /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
1845 /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
1846 UNNAMEABLE_TEST_ITEMS,
1848 "detects an item that cannot be named being marked as `#[test_case]`",
1849 report_in_external_macro
1852 pub struct UnnameableTestItems {
1853 boundary: Option<LocalDefId>, // Id of the item under which things are not nameable
1854 items_nameable: bool,
1857 impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1859 impl UnnameableTestItems {
1860 pub fn new() -> Self {
1861 Self { boundary: None, items_nameable: true }
1865 impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
1866 fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1867 if self.items_nameable {
1868 if let hir::ItemKind::Mod(..) = it.kind {
1870 self.items_nameable = false;
1871 self.boundary = Some(it.def_id);
1876 let attrs = cx.tcx.hir().attrs(it.hir_id());
1877 if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
1878 cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
1879 lint.build(fluent::lint::builtin_unnameable_test_items).emit();
1884 fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
1885 if !self.items_nameable && self.boundary == Some(it.def_id) {
1886 self.items_nameable = true;
1892 /// The `keyword_idents` lint detects edition keywords being used as an
1897 /// ```rust,edition2015,compile_fail
1898 /// #![deny(keyword_idents)]
1907 /// Rust [editions] allow the language to evolve without breaking
1908 /// backwards compatibility. This lint catches code that uses new keywords
1909 /// that are added to the language that are used as identifiers (such as a
1910 /// variable name, function name, etc.). If you switch the compiler to a
1911 /// new edition without updating the code, then it will fail to compile if
1912 /// you are using a new keyword as an identifier.
1914 /// You can manually change the identifiers to a non-keyword, or use a
1915 /// [raw identifier], for example `r#dyn`, to transition to a new edition.
1917 /// This lint solves the problem automatically. It is "allow" by default
1918 /// because the code is perfectly valid in older editions. The [`cargo
1919 /// fix`] tool with the `--edition` flag will switch this lint to "warn"
1920 /// and automatically apply the suggested fix from the compiler (which is
1921 /// to use a raw identifier). This provides a completely automated way to
1922 /// update old code for a new edition.
1924 /// [editions]: https://doc.rust-lang.org/edition-guide/
1925 /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
1926 /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
1929 "detects edition keywords being used as an identifier",
1930 @future_incompatible = FutureIncompatibleInfo {
1931 reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
1932 reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
1937 /// Check for uses of edition keywords used as an identifier.
1938 KeywordIdents => [KEYWORD_IDENTS]
1941 struct UnderMacro(bool);
1943 impl KeywordIdents {
1944 fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
1945 for tt in tokens.into_trees() {
1947 // Only report non-raw idents.
1948 TokenTree::Token(token, _) => {
1949 if let Some((ident, false)) = token.ident() {
1950 self.check_ident_token(cx, UnderMacro(true), ident);
1953 TokenTree::Delimited(_, _, tts) => self.check_tokens(cx, tts),
1958 fn check_ident_token(
1960 cx: &EarlyContext<'_>,
1961 UnderMacro(under_macro): UnderMacro,
1964 let next_edition = match cx.sess().edition() {
1965 Edition::Edition2015 => {
1967 kw::Async | kw::Await | kw::Try => Edition::Edition2018,
1969 // rust-lang/rust#56327: Conservatively do not
1970 // attempt to report occurrences of `dyn` within
1971 // macro definitions or invocations, because `dyn`
1972 // can legitimately occur as a contextual keyword
1973 // in 2015 code denoting its 2018 meaning, and we
1974 // do not want rustfix to inject bugs into working
1975 // code by rewriting such occurrences.
1977 // But if we see `dyn` outside of a macro, we know
1978 // its precise role in the parsed AST and thus are
1979 // assured this is truly an attempt to use it as
1981 kw::Dyn if !under_macro => Edition::Edition2018,
1987 // There are no new keywords yet for the 2018 edition and beyond.
1991 // Don't lint `r#foo`.
1992 if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1996 cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
1997 lint.build(fluent::lint::builtin_keyword_idents)
1998 .set_arg("kw", ident.clone())
1999 .set_arg("next", next_edition)
2002 fluent::lint::suggestion,
2003 format!("r#{}", ident),
2004 Applicability::MachineApplicable,
2011 impl EarlyLintPass for KeywordIdents {
2012 fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
2013 self.check_tokens(cx, mac_def.body.inner_tokens());
2015 fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
2016 self.check_tokens(cx, mac.args.inner_tokens());
2018 fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
2019 self.check_ident_token(cx, UnderMacro(false), ident);
2023 declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
2025 impl ExplicitOutlivesRequirements {
2026 fn lifetimes_outliving_lifetime<'tcx>(
2027 inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2029 ) -> Vec<ty::Region<'tcx>> {
2032 .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2033 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
2034 ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
2042 fn lifetimes_outliving_type<'tcx>(
2043 inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
2045 ) -> Vec<ty::Region<'tcx>> {
2048 .filter_map(|(pred, _)| match pred.kind().skip_binder() {
2049 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
2050 a.is_param(index).then_some(b)
2057 fn collect_outlives_bound_spans<'tcx>(
2060 bounds: &hir::GenericBounds<'_>,
2061 inferred_outlives: &[ty::Region<'tcx>],
2062 ) -> Vec<(usize, Span)> {
2063 use rustc_middle::middle::resolve_lifetime::Region;
2068 .filter_map(|(i, bound)| {
2069 if let hir::GenericBound::Outlives(lifetime) = bound {
2070 let is_inferred = match tcx.named_region(lifetime.hir_id) {
2071 Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
2072 if let ty::ReEarlyBound(ebr) = **r {
2073 ebr.def_id == def_id
2080 is_inferred.then_some((i, bound.span()))
2085 .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
2089 fn consolidate_outlives_bound_spans(
2092 bounds: &hir::GenericBounds<'_>,
2093 bound_spans: Vec<(usize, Span)>,
2095 if bounds.is_empty() {
2098 if bound_spans.len() == bounds.len() {
2099 let (_, last_bound_span) = bound_spans[bound_spans.len() - 1];
2100 // If all bounds are inferable, we want to delete the colon, so
2101 // start from just after the parameter (span passed as argument)
2102 vec![lo.to(last_bound_span)]
2104 let mut merged = Vec::new();
2105 let mut last_merged_i = None;
2107 let mut from_start = true;
2108 for (i, bound_span) in bound_spans {
2109 match last_merged_i {
2110 // If the first bound is inferable, our span should also eat the leading `+`.
2112 merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
2113 last_merged_i = Some(0);
2115 // If consecutive bounds are inferable, merge their spans
2116 Some(h) if i == h + 1 => {
2117 if let Some(tail) = merged.last_mut() {
2118 // Also eat the trailing `+` if the first
2119 // more-than-one bound is inferable
2120 let to_span = if from_start && i < bounds.len() {
2121 bounds[i + 1].span().shrink_to_lo()
2125 *tail = tail.to(to_span);
2126 last_merged_i = Some(i);
2128 bug!("another bound-span visited earlier");
2132 // When we find a non-inferable bound, subsequent inferable bounds
2133 // won't be consecutive from the start (and we'll eat the leading
2134 // `+` rather than the trailing one)
2136 merged.push(bounds[i - 1].span().shrink_to_hi().to(bound_span));
2137 last_merged_i = Some(i);
2146 impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
2147 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
2148 use rustc_middle::middle::resolve_lifetime::Region;
2150 let def_id = item.def_id;
2151 if let hir::ItemKind::Struct(_, ref hir_generics)
2152 | hir::ItemKind::Enum(_, ref hir_generics)
2153 | hir::ItemKind::Union(_, ref hir_generics) = item.kind
2155 let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
2156 if inferred_outlives.is_empty() {
2160 let ty_generics = cx.tcx.generics_of(def_id);
2162 let mut bound_count = 0;
2163 let mut lint_spans = Vec::new();
2164 let mut where_lint_spans = Vec::new();
2165 let mut dropped_predicate_count = 0;
2166 let num_predicates = hir_generics.predicates.len();
2167 for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
2168 let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
2169 hir::WherePredicate::RegionPredicate(predicate) => {
2170 if let Some(Region::EarlyBound(region_def_id)) =
2171 cx.tcx.named_region(predicate.lifetime.hir_id)
2174 Self::lifetimes_outliving_lifetime(
2180 predicate.in_where_clause,
2186 hir::WherePredicate::BoundPredicate(predicate) => {
2187 // FIXME we can also infer bounds on associated types,
2188 // and should check for them here.
2189 match predicate.bounded_ty.kind {
2190 hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2191 let Res::Def(DefKind::TyParam, def_id) = path.res else {
2194 let index = ty_generics.param_def_id_to_index[&def_id];
2196 Self::lifetimes_outliving_type(inferred_outlives, index),
2199 predicate.origin == PredicateOrigin::WhereClause,
2209 if relevant_lifetimes.is_empty() {
2214 self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
2215 bound_count += bound_spans.len();
2217 let drop_predicate = bound_spans.len() == bounds.len();
2219 dropped_predicate_count += 1;
2222 if drop_predicate && !in_where_clause {
2223 lint_spans.push(span);
2224 } else if drop_predicate && i + 1 < num_predicates {
2225 // If all the bounds on a predicate were inferable and there are
2226 // further predicates, we want to eat the trailing comma.
2227 let next_predicate_span = hir_generics.predicates[i + 1].span();
2228 where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
2230 where_lint_spans.extend(self.consolidate_outlives_bound_spans(
2231 span.shrink_to_lo(),
2238 // If all predicates are inferable, drop the entire clause
2239 // (including the `where`)
2240 if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
2242 let where_span = hir_generics.where_clause_span;
2243 // Extend the where clause back to the closing `>` of the
2244 // generics, except for tuple struct, which have the `where`
2245 // after the fields of the struct.
2246 let full_where_span =
2247 if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
2250 hir_generics.span.shrink_to_hi().to(where_span)
2252 lint_spans.push(full_where_span);
2254 lint_spans.extend(where_lint_spans);
2257 if !lint_spans.is_empty() {
2258 cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
2259 lint.build(fluent::lint::builtin_explicit_outlives)
2260 .set_arg("count", bound_count)
2261 .multipart_suggestion(
2262 fluent::lint::suggestion,
2265 .map(|span| (span, String::new()))
2266 .collect::<Vec<_>>(),
2267 Applicability::MachineApplicable,
2277 /// The `incomplete_features` lint detects unstable features enabled with
2278 /// the [`feature` attribute] that may function improperly in some or all
2281 /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
2286 /// #![feature(generic_const_exprs)]
2293 /// Although it is encouraged for people to experiment with unstable
2294 /// features, some of them are known to be incomplete or faulty. This lint
2295 /// is a signal that the feature has not yet been finished, and you may
2296 /// experience problems with it.
2297 pub INCOMPLETE_FEATURES,
2299 "incomplete features that may function improperly in some or all cases"
2303 /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
2304 IncompleteFeatures => [INCOMPLETE_FEATURES]
2307 impl EarlyLintPass for IncompleteFeatures {
2308 fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
2309 let features = cx.sess().features_untracked();
2311 .declared_lang_features
2313 .map(|(name, span, _)| (name, span))
2314 .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
2315 .filter(|(&name, _)| features.incomplete(name))
2316 .for_each(|(&name, &span)| {
2317 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
2318 let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
2319 builder.set_arg("name", name);
2320 if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
2321 builder.set_arg("n", n);
2322 builder.note(fluent::lint::note);
2324 if HAS_MIN_FEATURES.contains(&name) {
2325 builder.help(fluent::lint::help);
2333 const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
2336 /// The `invalid_value` lint detects creating a value that is not valid,
2337 /// such as a null reference.
2342 /// # #![allow(unused)]
2344 /// let x: &'static i32 = std::mem::zeroed();
2352 /// In some situations the compiler can detect that the code is creating
2353 /// an invalid value, which should be avoided.
2355 /// In particular, this lint will check for improper use of
2356 /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
2357 /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
2358 /// lint should provide extra information to indicate what the problem is
2359 /// and a possible solution.
2361 /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
2362 /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
2363 /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
2364 /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
2365 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
2368 "an invalid value is being created (such as a null reference)"
2371 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
2373 impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2374 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
2375 #[derive(Debug, Copy, Clone, PartialEq)]
2381 /// Information about why a type cannot be initialized this way.
2382 /// Contains an error message and optionally a span to point at.
2383 type InitError = (String, Option<Span>);
2385 /// Test if this constant is all-0.
2386 fn is_zero(expr: &hir::Expr<'_>) -> bool {
2387 use hir::ExprKind::*;
2388 use rustc_ast::LitKind::*;
2391 if let Int(i, _) = lit.node {
2397 Tup(tup) => tup.iter().all(is_zero),
2402 /// Determine if this expression is a "dangerous initialization".
2403 fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
2404 if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
2405 // Find calls to `mem::{uninitialized,zeroed}` methods.
2406 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2407 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2408 match cx.tcx.get_diagnostic_name(def_id) {
2409 Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2410 Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2411 Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2415 } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
2416 // Find problematic calls to `MaybeUninit::assume_init`.
2417 let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
2418 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
2419 // This is a call to *some* method named `assume_init`.
2420 // See if the `self` parameter is one of the dangerous constructors.
2421 if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
2422 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
2423 let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2424 match cx.tcx.get_diagnostic_name(def_id) {
2425 Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2426 Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2437 /// Test if this enum has several actually "existing" variants.
2438 /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
2439 fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
2440 // As an approximation, we only count dataless variants. Those are definitely inhabited.
2441 let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
2442 existing_variants > 1
2445 /// Return `Some` only if we are sure this type does *not*
2446 /// allow zero initialization.
2447 fn ty_find_init_error<'tcx>(
2448 cx: &LateContext<'tcx>,
2451 ) -> Option<InitError> {
2452 use rustc_type_ir::sty::TyKind::*;
2454 // Primitive types that don't like 0 as a value.
2455 Ref(..) => Some(("references must be non-null".to_string(), None)),
2456 Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)),
2457 FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)),
2458 Never => Some(("the `!` type has no valid value".to_string(), None)),
2459 RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) =>
2460 // raw ptr to dyn Trait
2462 Some(("the vtable of a wide raw pointer must be non-null".to_string(), None))
2464 // Primitive types with other constraints.
2465 Bool if init == InitKind::Uninit => {
2466 Some(("booleans must be either `true` or `false`".to_string(), None))
2468 Char if init == InitKind::Uninit => {
2469 Some(("characters must be a valid Unicode codepoint".to_string(), None))
2471 Int(_) | Uint(_) if init == InitKind::Uninit => {
2472 Some(("integers must not be uninitialized".to_string(), None))
2474 Float(_) if init == InitKind::Uninit => {
2475 Some(("floats must not be uninitialized".to_string(), None))
2477 RawPtr(_) if init == InitKind::Uninit => {
2478 Some(("raw pointers must not be uninitialized".to_string(), None))
2480 // Recurse and checks for some compound types.
2481 Adt(adt_def, substs) if !adt_def.is_union() => {
2482 // First check if this ADT has a layout attribute (like `NonNull` and friends).
2483 use std::ops::Bound;
2484 match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
2485 // We exploit here that `layout_scalar_valid_range` will never
2486 // return `Bound::Excluded`. (And we have tests checking that we
2487 // handle the attribute correctly.)
2488 (Bound::Included(lo), _) if lo > 0 => {
2489 return Some((format!("`{}` must be non-null", ty), None));
2491 (Bound::Included(_), _) | (_, Bound::Included(_))
2492 if init == InitKind::Uninit =>
2496 "`{}` must be initialized inside its custom valid range",
2505 match adt_def.variants().len() {
2506 0 => Some(("enums with no variants have no valid value".to_string(), None)),
2508 // Struct, or enum with exactly one variant.
2509 // Proceed recursively, check all fields.
2510 let variant = &adt_def.variant(VariantIdx::from_u32(0));
2511 variant.fields.iter().find_map(|field| {
2512 ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
2515 // Point to this field, should be helpful for figuring
2516 // out where the source of the error is.
2517 let span = cx.tcx.def_span(field.did);
2520 " (in this {} field)",
2533 // Multi-variant enum.
2535 if init == InitKind::Uninit && is_multi_variant(*adt_def) {
2536 let span = cx.tcx.def_span(adt_def.did());
2538 "enums have to be initialized to a variant".to_string(),
2542 // In principle, for zero-initialization we could figure out which variant corresponds
2543 // to tag 0, and check that... but for now we just accept all zero-initializations.
2550 // Proceed recursively, check all fields.
2551 ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
2554 if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
2555 // Array length known at array non-empty -- recurse.
2556 ty_find_init_error(cx, *ty, init)
2558 // Empty array or size unknown.
2562 // Conservative fallback.
2567 if let Some(init) = is_dangerous_init(cx, expr) {
2568 // This conjures an instance of a type out of nothing,
2569 // using zeroed or uninitialized memory.
2570 // We are extremely conservative with what we warn about.
2571 let conjured_ty = cx.typeck_results().expr_ty(expr);
2572 if let Some((msg, span)) =
2573 with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
2575 // FIXME(davidtwco): make translatable
2576 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
2577 let mut err = lint.build(&format!(
2578 "the type `{}` does not permit {}",
2581 InitKind::Zeroed => "zero-initialization",
2582 InitKind::Uninit => "being left uninitialized",
2585 err.span_label(expr.span, "this code causes undefined behavior when executed");
2588 "help: use `MaybeUninit<T>` instead, \
2589 and only call `assume_init` after initialization is done",
2591 if let Some(span) = span {
2592 err.span_note(span, &msg);
2604 /// The `clashing_extern_declarations` lint detects when an `extern fn`
2605 /// has been declared with the same name but different types.
2625 /// Because two symbols of the same name cannot be resolved to two
2626 /// different functions at link time, and one function cannot possibly
2627 /// have two types, a clashing extern declaration is almost certainly a
2628 /// mistake. Check to make sure that the `extern` definitions are correct
2629 /// and equivalent, and possibly consider unifying them in one location.
2631 /// This lint does not run between crates because a project may have
2632 /// dependencies which both rely on the same extern function, but declare
2633 /// it in a different (but valid) way. For example, they may both declare
2634 /// an opaque type for one or more of the arguments (which would end up
2635 /// distinct types), or use types that are valid conversions in the
2636 /// language the `extern fn` is defined in. In these cases, the compiler
2637 /// can't say that the clashing declaration is incorrect.
2638 pub CLASHING_EXTERN_DECLARATIONS,
2640 "detects when an extern fn has been declared with the same name but different types"
2643 pub struct ClashingExternDeclarations {
2644 /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
2645 /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
2646 /// the symbol should be reported as a clashing declaration.
2647 // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
2648 // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
2649 seen_decls: FxHashMap<Symbol, HirId>,
2652 /// Differentiate between whether the name for an extern decl came from the link_name attribute or
2653 /// just from declaration itself. This is important because we don't want to report clashes on
2654 /// symbol name if they don't actually clash because one or the other links against a symbol with a
2657 /// The name of the symbol + the span of the annotation which introduced the link name.
2659 /// No link name, so just the name of the symbol.
2664 fn get_name(&self) -> Symbol {
2666 SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
2671 impl ClashingExternDeclarations {
2672 pub(crate) fn new() -> Self {
2673 ClashingExternDeclarations { seen_decls: FxHashMap::default() }
2675 /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
2676 /// for the item, return its HirId without updating the set.
2677 fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
2678 let did = fi.def_id.to_def_id();
2679 let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
2680 let name = Symbol::intern(tcx.symbol_name(instance).name);
2681 if let Some(&hir_id) = self.seen_decls.get(&name) {
2682 // Avoid updating the map with the new entry when we do find a collision. We want to
2683 // make sure we're always pointing to the first definition as the previous declaration.
2684 // This lets us avoid emitting "knock-on" diagnostics.
2687 self.seen_decls.insert(name, fi.hir_id())
2691 /// Get the name of the symbol that's linked against for a given extern declaration. That is,
2692 /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
2694 fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
2695 if let Some((overridden_link_name, overridden_link_name_span)) =
2696 tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
2697 // FIXME: Instead of searching through the attributes again to get span
2698 // information, we could have codegen_fn_attrs also give span information back for
2699 // where the attribute was defined. However, until this is found to be a
2700 // bottleneck, this does just fine.
2702 overridden_link_name,
2703 tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
2707 SymbolName::Link(overridden_link_name, overridden_link_name_span)
2709 SymbolName::Normal(fi.ident.name)
2713 /// Checks whether two types are structurally the same enough that the declarations shouldn't
2714 /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
2715 /// with the same members (as the declarations shouldn't clash).
2716 fn structurally_same_type<'tcx>(
2717 cx: &LateContext<'tcx>,
2722 fn structurally_same_type_impl<'tcx>(
2723 seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
2724 cx: &LateContext<'tcx>,
2729 debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2732 // Given a transparent newtype, reach through and grab the inner
2733 // type unless the newtype makes the type non-null.
2734 let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
2737 if let ty::Adt(def, substs) = *ty.kind() {
2738 let is_transparent = def.repr().transparent();
2739 let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
2741 "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
2742 ty, is_transparent, is_non_null
2744 if is_transparent && !is_non_null {
2745 debug_assert!(def.variants().len() == 1);
2746 let v = &def.variant(VariantIdx::new(0));
2747 ty = transparent_newtype_field(tcx, v)
2749 "single-variant transparent structure with zero-sized field",
2755 debug!("non_transparent_ty -> {:?}", ty);
2760 let a = non_transparent_ty(a);
2761 let b = non_transparent_ty(b);
2763 if !seen_types.insert((a, b)) {
2764 // We've encountered a cycle. There's no point going any further -- the types are
2765 // structurally the same.
2770 // All nominally-same types are structurally same, too.
2773 // Do a full, depth-first comparison between the two.
2774 use rustc_type_ir::sty::TyKind::*;
2775 let a_kind = a.kind();
2776 let b_kind = b.kind();
2778 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
2779 debug!("compare_layouts({:?}, {:?})", a, b);
2780 let a_layout = &cx.layout_of(a)?.layout.abi();
2781 let b_layout = &cx.layout_of(b)?.layout.abi();
2783 "comparing layouts: {:?} == {:?} = {}",
2786 a_layout == b_layout
2788 Ok(a_layout == b_layout)
2791 #[allow(rustc::usage_of_ty_tykind)]
2792 let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
2793 kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
2796 ensure_sufficient_stack(|| {
2797 match (a_kind, b_kind) {
2798 (Adt(a_def, _), Adt(b_def, _)) => {
2799 // We can immediately rule out these types as structurally same if
2800 // their layouts differ.
2801 match compare_layouts(a, b) {
2802 Ok(false) => return false,
2803 _ => (), // otherwise, continue onto the full, fields comparison
2806 // Grab a flattened representation of all fields.
2807 let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
2808 let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
2810 // Perform a structural comparison for each field.
2813 |&ty::FieldDef { did: a_did, .. },
2814 &ty::FieldDef { did: b_did, .. }| {
2815 structurally_same_type_impl(
2825 (Array(a_ty, a_const), Array(b_ty, b_const)) => {
2826 // For arrays, we also check the constness of the type.
2827 a_const.kind() == b_const.kind()
2828 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2830 (Slice(a_ty), Slice(b_ty)) => {
2831 structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2833 (RawPtr(a_tymut), RawPtr(b_tymut)) => {
2834 a_tymut.mutbl == b_tymut.mutbl
2835 && structurally_same_type_impl(
2836 seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
2839 (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
2840 // For structural sameness, we don't need the region to be same.
2842 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
2844 (FnDef(..), FnDef(..)) => {
2845 let a_poly_sig = a.fn_sig(tcx);
2846 let b_poly_sig = b.fn_sig(tcx);
2848 // We don't compare regions, but leaving bound regions around ICEs, so
2850 let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
2851 let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
2853 (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
2854 == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
2855 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2856 structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
2858 && structurally_same_type_impl(
2866 (Tuple(a_substs), Tuple(b_substs)) => {
2867 a_substs.iter().eq_by(b_substs.iter(), |a_ty, b_ty| {
2868 structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2871 // For these, it's not quite as easy to define structural-sameness quite so easily.
2872 // For the purposes of this lint, take the conservative approach and mark them as
2873 // not structurally same.
2874 (Dynamic(..), Dynamic(..))
2875 | (Error(..), Error(..))
2876 | (Closure(..), Closure(..))
2877 | (Generator(..), Generator(..))
2878 | (GeneratorWitness(..), GeneratorWitness(..))
2879 | (Projection(..), Projection(..))
2880 | (Opaque(..), Opaque(..)) => false,
2882 // These definitely should have been caught above.
2883 (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
2885 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
2886 // enum layout optimisation is being applied.
2887 (Adt(..), other_kind) | (other_kind, Adt(..))
2888 if is_primitive_or_pointer(other_kind) =>
2890 let (primitive, adt) =
2891 if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
2892 if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2895 compare_layouts(a, b).unwrap_or(false)
2898 // Otherwise, just compare the layouts. This may fail to lint for some
2899 // incompatible types, but at the very least, will stop reads into
2900 // uninitialised memory.
2901 _ => compare_layouts(a, b).unwrap_or(false),
2906 let mut seen_types = FxHashSet::default();
2907 structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
2911 impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
2913 impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
2914 fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
2915 trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
2916 if let ForeignItemKind::Fn(..) = this_fi.kind {
2918 if let Some(existing_hid) = self.insert(tcx, this_fi) {
2919 let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
2920 let this_decl_ty = tcx.type_of(this_fi.def_id);
2922 "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
2923 existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
2925 // Check that the declarations match.
2926 if !Self::structurally_same_type(
2930 CItemKind::Declaration,
2932 let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
2933 let orig = Self::name_of_extern_decl(tcx, orig_fi);
2935 // We want to ensure that we use spans for both decls that include where the
2936 // name was defined, whether that was from the link_name attribute or not.
2937 let get_relevant_span =
2938 |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
2939 SymbolName::Normal(_) => fi.span,
2940 SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
2942 // Finally, emit the diagnostic.
2943 tcx.struct_span_lint_hir(
2944 CLASHING_EXTERN_DECLARATIONS,
2946 get_relevant_span(this_fi),
2948 let mut expected_str = DiagnosticStyledString::new();
2949 expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
2950 let mut found_str = DiagnosticStyledString::new();
2951 found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
2953 lint.build(if orig.get_name() == this_fi.ident.name {
2954 fluent::lint::builtin_clashing_extern_same_name
2956 fluent::lint::builtin_clashing_extern_diff_name
2958 .set_arg("this_fi", this_fi.ident.name)
2959 .set_arg("orig", orig.get_name())
2961 get_relevant_span(orig_fi),
2962 fluent::lint::previous_decl_label,
2964 .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
2965 // FIXME(davidtwco): translatable expected/found
2966 .note_expected_found(&"", expected_str, &"", found_str)
2977 /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2978 /// which causes [undefined behavior].
2983 /// # #![allow(unused)]
2986 /// let x = &*ptr::null::<i32>();
2987 /// let x = ptr::addr_of!(*ptr::null::<i32>());
2988 /// let x = *(0 as *const i32);
2996 /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
2997 /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
2999 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
3002 "detects when an null pointer is dereferenced"
3005 declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
3007 impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
3008 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
3009 /// test if expression is a null ptr
3010 fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
3012 rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
3013 if let rustc_hir::TyKind::Ptr(_) = ty.kind {
3014 return is_zero(expr) || is_null_ptr(cx, expr);
3017 // check for call to `core::ptr::null` or `core::ptr::null_mut`
3018 rustc_hir::ExprKind::Call(ref path, _) => {
3019 if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
3020 if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
3022 cx.tcx.get_diagnostic_name(def_id),
3023 Some(sym::ptr_null | sym::ptr_null_mut)
3033 /// test if expression is the literal `0`
3034 fn is_zero(expr: &hir::Expr<'_>) -> bool {
3036 rustc_hir::ExprKind::Lit(ref lit) => {
3037 if let LitKind::Int(a, _) = lit.node {
3046 if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
3047 if is_null_ptr(cx, expr_deref) {
3048 cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
3049 let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
3050 err.span_label(expr.span, fluent::lint::label);
3059 /// The `named_asm_labels` lint detects the use of named labels in the
3060 /// inline `asm!` macro.
3064 /// ```rust,compile_fail
3065 /// use std::arch::asm;
3069 /// asm!("foo: bar");
3078 /// LLVM is allowed to duplicate inline assembly blocks for any
3079 /// reason, for example when it is in a function that gets inlined. Because
3080 /// of this, GNU assembler [local labels] *must* be used instead of labels
3081 /// with a name. Using named labels might cause assembler or linker errors.
3083 /// See the explanation in [Rust By Example] for more details.
3085 /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
3086 /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
3087 pub NAMED_ASM_LABELS,
3089 "named labels in inline assembly",
3092 declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
3094 impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
3095 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
3097 kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
3101 for (template_sym, template_snippet, template_span) in template_strs.iter() {
3102 let template_str = template_sym.as_str();
3103 let find_label_span = |needle: &str| -> Option<Span> {
3104 if let Some(template_snippet) = template_snippet {
3105 let snippet = template_snippet.as_str();
3106 if let Some(pos) = snippet.find(needle) {
3110 .unwrap_or(snippet[pos..].len() - 1);
3111 let inner = InnerSpan::new(pos, end);
3112 return Some(template_span.from_inner(inner));
3119 let mut found_labels = Vec::new();
3121 // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
3122 let statements = template_str.split(|c| matches!(c, '\n' | ';'));
3123 for statement in statements {
3124 // If there's a comment, trim it from the statement
3125 let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
3126 let mut start_idx = 0;
3127 for (idx, _) in statement.match_indices(':') {
3128 let possible_label = statement[start_idx..idx].trim();
3129 let mut chars = possible_label.chars();
3130 let Some(c) = chars.next() else {
3131 // Empty string means a leading ':' in this section, which is not a label
3134 // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
3135 if (c.is_alphabetic() || matches!(c, '.' | '_'))
3136 && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
3138 found_labels.push(possible_label);
3140 // If we encounter a non-label, there cannot be any further labels, so stop checking
3144 start_idx = idx + 1;
3148 debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
3150 if found_labels.len() > 0 {
3151 let spans = found_labels
3153 .filter_map(|label| find_label_span(label))
3154 .collect::<Vec<Span>>();
3155 // If there were labels but we couldn't find a span, combine the warnings and use the template span
3156 let target_spans: MultiSpan =
3157 if spans.len() > 0 { spans.into() } else { (*template_span).into() };
3159 cx.lookup_with_diagnostics(
3163 diag.build(fluent::lint::builtin_asm_labels).emit();
3165 BuiltinLintDiagnostics::NamedAsmLabel(
3166 "only local labels of the form `<number>:` should be used in inline asm"
3177 /// The `special_module_name` lint detects module
3178 /// declarations for files that have a special meaning.
3182 /// ```rust,compile_fail
3194 /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
3195 /// library or binary crate, so declaring them as modules
3196 /// will lead to miscompilation of the crate unless configured
3199 /// To access a library from a binary target within the same crate,
3200 /// use `your_crate_name::` as the path path instead of `lib::`:
3202 /// ```rust,compile_fail
3203 /// // bar/src/lib.rs
3208 /// // bar/src/main.rs
3214 /// Binary targets cannot be used as libraries and so declaring
3215 /// one as a module is not allowed.
3216 pub SPECIAL_MODULE_NAME,
3218 "module declarations for files with a special meaning",
3221 declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
3223 impl EarlyLintPass for SpecialModuleName {
3224 fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
3225 for item in &krate.items {
3226 if let ast::ItemKind::Mod(
3228 ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
3231 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
3235 match item.ident.name.as_str() {
3236 "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3237 lint.build("found module declaration for lib.rs")
3238 .note("lib.rs is the root of this crate's library target")
3239 .help("to refer to it from other targets, use the library's name as the path")
3242 "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
3243 lint.build("found module declaration for main.rs")
3244 .note("a binary crate cannot be used as library")