| //! Some lints that are built in to the compiler. |
| //! |
| //! These are the built-in lints that are emitted direct in the main |
| //! compiler code, rather than using their own custom pass. Those |
| //! lints are all available in `rustc_lint::builtin`. |
| |
| use crate::lint::{LintPass, LateLintPass, LintArray}; |
| use crate::middle::stability; |
| use crate::session::Session; |
| use errors::{Applicability, DiagnosticBuilder}; |
| use syntax::ast; |
| use syntax::source_map::Span; |
| use syntax::symbol::Symbol; |
| |
| declare_lint! { |
| pub EXCEEDING_BITSHIFTS, |
| Deny, |
| "shift exceeds the type's number of bits" |
| } |
| |
| declare_lint! { |
| pub CONST_ERR, |
| Deny, |
| "constant evaluation detected erroneous expression" |
| } |
| |
| declare_lint! { |
| pub UNUSED_IMPORTS, |
| Warn, |
| "imports that are never used" |
| } |
| |
| declare_lint! { |
| pub UNUSED_EXTERN_CRATES, |
| Allow, |
| "extern crates that are never used" |
| } |
| |
| declare_lint! { |
| pub UNUSED_QUALIFICATIONS, |
| Allow, |
| "detects unnecessarily qualified names" |
| } |
| |
| declare_lint! { |
| pub UNKNOWN_LINTS, |
| Warn, |
| "unrecognized lint attribute" |
| } |
| |
| declare_lint! { |
| pub UNUSED_VARIABLES, |
| Warn, |
| "detect variables which are not used in any way" |
| } |
| |
| declare_lint! { |
| pub UNUSED_ASSIGNMENTS, |
| Warn, |
| "detect assignments that will never be read" |
| } |
| |
| declare_lint! { |
| pub DEAD_CODE, |
| Warn, |
| "detect unused, unexported items" |
| } |
| |
| declare_lint! { |
| pub UNREACHABLE_CODE, |
| Warn, |
| "detects unreachable code paths", |
| report_in_external_macro: true |
| } |
| |
| declare_lint! { |
| pub UNREACHABLE_PATTERNS, |
| Warn, |
| "detects unreachable patterns" |
| } |
| |
| declare_lint! { |
| pub UNUSED_MACROS, |
| Warn, |
| "detects macros that were not used" |
| } |
| |
| declare_lint! { |
| pub WARNINGS, |
| Warn, |
| "mass-change the level for lints which produce warnings" |
| } |
| |
| declare_lint! { |
| pub UNUSED_FEATURES, |
| Warn, |
| "unused features found in crate-level `#[feature]` directives" |
| } |
| |
| declare_lint! { |
| pub STABLE_FEATURES, |
| Warn, |
| "stable features found in `#[feature]` directive" |
| } |
| |
| declare_lint! { |
| pub UNKNOWN_CRATE_TYPES, |
| Deny, |
| "unknown crate type found in `#[crate_type]` directive" |
| } |
| |
| declare_lint! { |
| pub TRIVIAL_CASTS, |
| Allow, |
| "detects trivial casts which could be removed" |
| } |
| |
| declare_lint! { |
| pub TRIVIAL_NUMERIC_CASTS, |
| Allow, |
| "detects trivial casts of numeric types which could be removed" |
| } |
| |
| declare_lint! { |
| pub PRIVATE_IN_PUBLIC, |
| Warn, |
| "detect private items in public interfaces not caught by the old implementation" |
| } |
| |
| declare_lint! { |
| pub EXPORTED_PRIVATE_DEPENDENCIES, |
| Warn, |
| "public interface leaks type from a private dependency" |
| } |
| |
| declare_lint! { |
| pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, |
| Deny, |
| "detect public re-exports of private extern crates" |
| } |
| |
| declare_lint! { |
| pub INVALID_TYPE_PARAM_DEFAULT, |
| Deny, |
| "type parameter default erroneously allowed in invalid location" |
| } |
| |
| declare_lint! { |
| pub RENAMED_AND_REMOVED_LINTS, |
| Warn, |
| "lints that have been renamed or removed" |
| } |
| |
| declare_lint! { |
| pub SAFE_EXTERN_STATICS, |
| Deny, |
| "safe access to extern statics was erroneously allowed" |
| } |
| |
| declare_lint! { |
| pub SAFE_PACKED_BORROWS, |
| Warn, |
| "safe borrows of fields of packed structs were was erroneously allowed" |
| } |
| |
| declare_lint! { |
| pub PATTERNS_IN_FNS_WITHOUT_BODY, |
| Warn, |
| "patterns in functions without body were erroneously allowed" |
| } |
| |
| declare_lint! { |
| pub LEGACY_DIRECTORY_OWNERSHIP, |
| Deny, |
| "non-inline, non-`#[path]` modules (e.g., `mod foo;`) were erroneously allowed in some files \ |
| not named `mod.rs`" |
| } |
| |
| declare_lint! { |
| pub LEGACY_CONSTRUCTOR_VISIBILITY, |
| Deny, |
| "detects use of struct constructors that would be invisible with new visibility rules" |
| } |
| |
| declare_lint! { |
| pub MISSING_FRAGMENT_SPECIFIER, |
| Deny, |
| "detects missing fragment specifiers in unused `macro_rules!` patterns" |
| } |
| |
| declare_lint! { |
| pub PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, |
| Deny, |
| "detects parenthesized generic parameters in type and module names" |
| } |
| |
| declare_lint! { |
| pub LATE_BOUND_LIFETIME_ARGUMENTS, |
| Warn, |
| "detects generic lifetime arguments in path segments with late bound lifetime parameters" |
| } |
| |
| declare_lint! { |
| pub ORDER_DEPENDENT_TRAIT_OBJECTS, |
| Deny, |
| "trait-object types were treated as different depending on marker-trait order" |
| } |
| |
| declare_lint! { |
| pub DEPRECATED, |
| Warn, |
| "detects use of deprecated items", |
| report_in_external_macro: true |
| } |
| |
| declare_lint! { |
| pub UNUSED_UNSAFE, |
| Warn, |
| "unnecessary use of an `unsafe` block" |
| } |
| |
| declare_lint! { |
| pub UNUSED_MUT, |
| Warn, |
| "detect mut variables which don't need to be mutable" |
| } |
| |
| declare_lint! { |
| pub UNCONDITIONAL_RECURSION, |
| Warn, |
| "functions that cannot return without calling themselves" |
| } |
| |
| declare_lint! { |
| pub SINGLE_USE_LIFETIMES, |
| Allow, |
| "detects lifetime parameters that are only used once" |
| } |
| |
| declare_lint! { |
| pub UNUSED_LIFETIMES, |
| Allow, |
| "detects lifetime parameters that are never used" |
| } |
| |
| declare_lint! { |
| pub TYVAR_BEHIND_RAW_POINTER, |
| Warn, |
| "raw pointer to an inference variable" |
| } |
| |
| declare_lint! { |
| pub ELIDED_LIFETIMES_IN_PATHS, |
| Allow, |
| "hidden lifetime parameters in types are deprecated" |
| } |
| |
| declare_lint! { |
| pub BARE_TRAIT_OBJECTS, |
| Warn, |
| "suggest using `dyn Trait` for trait objects" |
| } |
| |
| declare_lint! { |
| pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, |
| Allow, |
| "fully qualified paths that start with a module name \ |
| instead of `crate`, `self`, or an extern crate name" |
| } |
| |
| declare_lint! { |
| pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, |
| Warn, |
| "floating-point literals cannot be used in patterns" |
| } |
| |
| declare_lint! { |
| pub UNSTABLE_NAME_COLLISIONS, |
| Warn, |
| "detects name collision with an existing but unstable method" |
| } |
| |
| declare_lint! { |
| pub IRREFUTABLE_LET_PATTERNS, |
| Warn, |
| "detects irrefutable patterns in if-let and while-let statements" |
| } |
| |
| declare_lint! { |
| pub UNUSED_LABELS, |
| Allow, |
| "detects labels that are never used" |
| } |
| |
| declare_lint! { |
| pub DUPLICATE_MACRO_EXPORTS, |
| Deny, |
| "detects duplicate macro exports" |
| } |
| |
| declare_lint! { |
| pub INTRA_DOC_LINK_RESOLUTION_FAILURE, |
| Warn, |
| "failures in resolving intra-doc link targets" |
| } |
| |
| declare_lint! { |
| pub MISSING_DOC_CODE_EXAMPLES, |
| Allow, |
| "detects publicly-exported items without code samples in their documentation" |
| } |
| |
| declare_lint! { |
| pub PRIVATE_DOC_TESTS, |
| Allow, |
| "detects code samples in docs of private items not documented by rustdoc" |
| } |
| |
| declare_lint! { |
| pub WHERE_CLAUSES_OBJECT_SAFETY, |
| Warn, |
| "checks the object safety of where clauses" |
| } |
| |
| declare_lint! { |
| pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, |
| Warn, |
| "detects proc macro derives using inaccessible names from parent modules" |
| } |
| |
| declare_lint! { |
| pub MACRO_USE_EXTERN_CRATE, |
| Allow, |
| "the `#[macro_use]` attribute is now deprecated in favor of using macros \ |
| via the module system" |
| } |
| |
| declare_lint! { |
| pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, |
| Deny, |
| "macro-expanded `macro_export` macros from the current crate \ |
| cannot be referred to by absolute paths" |
| } |
| |
| declare_lint! { |
| pub EXPLICIT_OUTLIVES_REQUIREMENTS, |
| Allow, |
| "outlives requirements can be inferred" |
| } |
| |
| declare_lint! { |
| pub INDIRECT_STRUCTURAL_MATCH, |
| // defaulting to allow until rust-lang/rust#62614 is fixed. |
| Allow, |
| "pattern with const indirectly referencing non-`#[structural_match]` type" |
| } |
| |
| /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`. |
| pub mod parser { |
| declare_lint! { |
| pub ILL_FORMED_ATTRIBUTE_INPUT, |
| Warn, |
| "ill-formed attribute inputs that were previously accepted and used in practice" |
| } |
| |
| declare_lint! { |
| pub META_VARIABLE_MISUSE, |
| Allow, |
| "possible meta-variable misuse at macro definition" |
| } |
| } |
| |
| declare_lint! { |
| pub DEPRECATED_IN_FUTURE, |
| Allow, |
| "detects use of items that will be deprecated in a future version", |
| report_in_external_macro: true |
| } |
| |
| declare_lint! { |
| pub AMBIGUOUS_ASSOCIATED_ITEMS, |
| Deny, |
| "ambiguous associated items" |
| } |
| |
| declare_lint! { |
| pub NESTED_IMPL_TRAIT, |
| Warn, |
| "nested occurrence of `impl Trait` type" |
| } |
| |
| declare_lint! { |
| pub MUTABLE_BORROW_RESERVATION_CONFLICT, |
| Warn, |
| "reservation of a two-phased borrow conflicts with other shared borrows" |
| } |
| |
| declare_lint! { |
| pub SOFT_UNSTABLE, |
| Deny, |
| "a feature gate that doesn't break dependent crates" |
| } |
| |
| declare_lint_pass! { |
| /// Does nothing as a lint pass, but registers some `Lint`s |
| /// that are used by other parts of the compiler. |
| HardwiredLints => [ |
| ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, |
| EXCEEDING_BITSHIFTS, |
| UNUSED_IMPORTS, |
| UNUSED_EXTERN_CRATES, |
| UNUSED_QUALIFICATIONS, |
| UNKNOWN_LINTS, |
| UNUSED_VARIABLES, |
| UNUSED_ASSIGNMENTS, |
| DEAD_CODE, |
| UNREACHABLE_CODE, |
| UNREACHABLE_PATTERNS, |
| UNUSED_MACROS, |
| WARNINGS, |
| UNUSED_FEATURES, |
| STABLE_FEATURES, |
| UNKNOWN_CRATE_TYPES, |
| TRIVIAL_CASTS, |
| TRIVIAL_NUMERIC_CASTS, |
| PRIVATE_IN_PUBLIC, |
| EXPORTED_PRIVATE_DEPENDENCIES, |
| PUB_USE_OF_PRIVATE_EXTERN_CRATE, |
| INVALID_TYPE_PARAM_DEFAULT, |
| CONST_ERR, |
| RENAMED_AND_REMOVED_LINTS, |
| SAFE_EXTERN_STATICS, |
| SAFE_PACKED_BORROWS, |
| PATTERNS_IN_FNS_WITHOUT_BODY, |
| LEGACY_DIRECTORY_OWNERSHIP, |
| LEGACY_CONSTRUCTOR_VISIBILITY, |
| MISSING_FRAGMENT_SPECIFIER, |
| PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, |
| LATE_BOUND_LIFETIME_ARGUMENTS, |
| ORDER_DEPENDENT_TRAIT_OBJECTS, |
| DEPRECATED, |
| UNUSED_UNSAFE, |
| UNUSED_MUT, |
| UNCONDITIONAL_RECURSION, |
| SINGLE_USE_LIFETIMES, |
| UNUSED_LIFETIMES, |
| UNUSED_LABELS, |
| TYVAR_BEHIND_RAW_POINTER, |
| ELIDED_LIFETIMES_IN_PATHS, |
| BARE_TRAIT_OBJECTS, |
| ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, |
| UNSTABLE_NAME_COLLISIONS, |
| IRREFUTABLE_LET_PATTERNS, |
| DUPLICATE_MACRO_EXPORTS, |
| INTRA_DOC_LINK_RESOLUTION_FAILURE, |
| MISSING_DOC_CODE_EXAMPLES, |
| PRIVATE_DOC_TESTS, |
| WHERE_CLAUSES_OBJECT_SAFETY, |
| PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, |
| MACRO_USE_EXTERN_CRATE, |
| MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, |
| parser::ILL_FORMED_ATTRIBUTE_INPUT, |
| parser::META_VARIABLE_MISUSE, |
| DEPRECATED_IN_FUTURE, |
| AMBIGUOUS_ASSOCIATED_ITEMS, |
| NESTED_IMPL_TRAIT, |
| MUTABLE_BORROW_RESERVATION_CONFLICT, |
| INDIRECT_STRUCTURAL_MATCH, |
| SOFT_UNSTABLE, |
| ] |
| } |
| |
| // this could be a closure, but then implementing derive traits |
| // becomes hacky (and it gets allocated) |
| #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] |
| pub enum BuiltinLintDiagnostics { |
| Normal, |
| BareTraitObject(Span, /* is_global */ bool), |
| AbsPathWithModule(Span), |
| DuplicatedMacroExports(ast::Ident, Span, Span), |
| ProcMacroDeriveResolutionFallback(Span), |
| MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), |
| ElidedLifetimesInPaths(usize, Span, bool, Span, String), |
| UnknownCrateTypes(Span, String, String), |
| UnusedImports(String, Vec<(Span, String)>), |
| NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span }, |
| RedundantImport(Vec<(Span, bool)>, ast::Ident), |
| DeprecatedMacro(Option<Symbol>, Span), |
| } |
| |
| pub(crate) fn add_elided_lifetime_in_path_suggestion( |
| sess: &Session, |
| db: &mut DiagnosticBuilder<'_>, |
| n: usize, |
| path_span: Span, |
| incl_angl_brckt: bool, |
| insertion_span: Span, |
| anon_lts: String, |
| ) { |
| let (replace_span, suggestion) = if incl_angl_brckt { |
| (insertion_span, anon_lts) |
| } else { |
| // When possible, prefer a suggestion that replaces the whole |
| // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, ` |
| // at a point (which makes for an ugly/confusing label) |
| if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { |
| // But our spans can get out of whack due to macros; if the place we think |
| // we want to insert `'_` isn't even within the path expression's span, we |
| // should bail out of making any suggestion rather than panicking on a |
| // subtract-with-overflow or string-slice-out-out-bounds (!) |
| // FIXME: can we do better? |
| if insertion_span.lo().0 < path_span.lo().0 { |
| return; |
| } |
| let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; |
| if insertion_index > snippet.len() { |
| return; |
| } |
| let (before, after) = snippet.split_at(insertion_index); |
| (path_span, format!("{}{}{}", before, anon_lts, after)) |
| } else { |
| (insertion_span, anon_lts) |
| } |
| }; |
| db.span_suggestion( |
| replace_span, |
| &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), |
| suggestion, |
| Applicability::MachineApplicable |
| ); |
| } |
| |
| impl BuiltinLintDiagnostics { |
| pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder<'_>) { |
| match self { |
| BuiltinLintDiagnostics::Normal => (), |
| BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { |
| let (sugg, app) = match sess.source_map().span_to_snippet(span) { |
| Ok(ref s) if is_global => (format!("dyn ({})", s), |
| Applicability::MachineApplicable), |
| Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable), |
| Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders) |
| }; |
| db.span_suggestion(span, "use `dyn`", sugg, app); |
| } |
| BuiltinLintDiagnostics::AbsPathWithModule(span) => { |
| let (sugg, app) = match sess.source_map().span_to_snippet(span) { |
| Ok(ref s) => { |
| // FIXME(Manishearth) ideally the emitting code |
| // can tell us whether or not this is global |
| let opt_colon = if s.trim_start().starts_with("::") { |
| "" |
| } else { |
| "::" |
| }; |
| |
| (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) |
| } |
| Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders) |
| }; |
| db.span_suggestion(span, "use `crate`", sugg, app); |
| } |
| BuiltinLintDiagnostics::DuplicatedMacroExports(ident, earlier_span, later_span) => { |
| db.span_label(later_span, format!("`{}` already exported", ident)); |
| db.span_note(earlier_span, "previous macro export is now shadowed"); |
| } |
| BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { |
| db.span_label(span, "names from parent modules are not \ |
| accessible without an explicit import"); |
| } |
| BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { |
| db.span_note(span_def, "the macro is defined here"); |
| } |
| BuiltinLintDiagnostics::ElidedLifetimesInPaths( |
| n, path_span, incl_angl_brckt, insertion_span, anon_lts |
| ) => { |
| add_elided_lifetime_in_path_suggestion( |
| sess, |
| db, |
| n, |
| path_span, |
| incl_angl_brckt, |
| insertion_span, |
| anon_lts, |
| ); |
| } |
| BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { |
| db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect); |
| } |
| BuiltinLintDiagnostics::UnusedImports(message, replaces) => { |
| if !replaces.is_empty() { |
| db.tool_only_multipart_suggestion( |
| &message, |
| replaces, |
| Applicability::MachineApplicable, |
| ); |
| } |
| } |
| BuiltinLintDiagnostics::NestedImplTrait { |
| outer_impl_trait_span, inner_impl_trait_span |
| } => { |
| db.span_label(outer_impl_trait_span, "outer `impl Trait`"); |
| db.span_label(inner_impl_trait_span, "nested `impl Trait` here"); |
| } |
| BuiltinLintDiagnostics::RedundantImport(spans, ident) => { |
| for (span, is_imported) in spans { |
| let introduced = if is_imported { "imported" } else { "defined" }; |
| db.span_label( |
| span, |
| format!("the item `{}` is already {} here", ident, introduced) |
| ); |
| } |
| } |
| BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => |
| stability::deprecation_suggestion(db, suggestion, span), |
| } |
| } |
| } |
| |
| impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {} |