From 3a2af3242c7009247e99e9bc087b1c0b72913d0f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 5 Jan 2020 10:58:44 +0100 Subject: [PATCH 01/14] canonicalize some lint imports --- src/librustc/hir/check_attr.rs | 2 +- src/librustc/lint/context.rs | 4 ++-- src/librustc/lint/levels.rs | 6 +++--- src/librustc/middle/stability.rs | 4 ++-- src/librustc/query/mod.rs | 2 +- src/librustc/traits/object_safety.rs | 7 +++--- src/librustc/traits/specialize/mod.rs | 4 ++-- src/librustc/ty/context.rs | 31 ++++++++++++++------------- src/librustc/ty/query/mod.rs | 2 +- src/librustc_ast_passes/Cargo.toml | 2 +- 10 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index c6a996f84f461..5a99e7965538b 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -5,7 +5,6 @@ //! item. use crate::hir::map::Map; -use crate::lint::builtin::UNUSED_ATTRIBUTES; use crate::ty::query::Providers; use crate::ty::TyCtxt; @@ -16,6 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::DUMMY_HIR_ID; use rustc_hir::{self, HirId, Item, ItemKind, TraitItem, TraitItemKind}; +use rustc_session::lint::builtin::UNUSED_ATTRIBUTES; use rustc_span::symbol::sym; use rustc_span::Span; use syntax::ast::Attribute; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 3f18f4dbd1fe7..867eb5a193707 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -16,12 +16,11 @@ use self::TargetLint::*; -use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; +use crate::hir::map::definitions::{DefPathData, DisambiguatedDefPathData}; use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; use crate::lint::{EarlyLintPassObject, LateLintPassObject}; use crate::middle::privacy::AccessLevels; use crate::middle::stability; -use crate::session::Session; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; @@ -32,6 +31,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; +use rustc_session::Session; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use syntax::ast; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index e586ad1836c73..fdd2a8d0778e2 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -1,14 +1,14 @@ use std::cmp; use crate::ich::StableHashingContext; -use crate::lint::builtin; use crate::lint::context::{CheckLintNameResult, LintStore}; -use crate::lint::{self, Level, Lint, LintId, LintSource}; -use crate::session::Session; +use crate::lint::{self, LintSource}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir::HirId; +use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::Session; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{sym, Symbol}; use syntax::ast; diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 17e84c24881c1..93fc09b4a2ac9 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -3,7 +3,7 @@ pub use self::StabilityLevel::*; -use crate::lint::{self, in_derive_expansion, Lint}; +use crate::lint::in_derive_expansion; use crate::session::{DiagnosticMessageId, Session}; use crate::ty::{self, TyCtxt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, HirId}; -use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::lint::{self, BuiltinLintDiagnostics, Lint, LintBuffer}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{MultiSpan, Span}; use syntax::ast::CRATE_NODE_ID; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 9de46f86200e1..eca9df688c64f 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -82,7 +82,7 @@ rustc_queries! { desc { "looking up the native libraries of a linked crate" } } - query lint_levels(_: CrateNum) -> &'tcx lint::LintLevelMap { + query lint_levels(_: CrateNum) -> &'tcx LintLevelMap { eval_always desc { "computing the lint levels for items in this crate" } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index bfbcb042e7a73..e4309dd28f4a1 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -10,17 +10,18 @@ use super::elaborate_predicates; -use crate::lint; use crate::traits::{self, Obligation, ObligationCause}; use crate::ty::subst::{InternalSubsts, Subst}; use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; +use syntax::ast; + use std::borrow::Cow; use std::iter::{self}; -use syntax::ast::{self}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { @@ -179,7 +180,7 @@ fn object_safety_violations_for_trait( // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // It's also hard to get a use site span, so we use the method definition span. tcx.lint_node_note( - lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, + WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, *span, &format!( diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 7b66341ef1c96..f5199dbdabb2f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -12,7 +12,6 @@ pub mod specialization_graph; use crate::infer::{InferCtxt, InferOk}; -use crate::lint; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; @@ -20,6 +19,7 @@ use crate::ty::{self, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir::def_id::DefId; +use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::DUMMY_SP; use super::util::impl_trait_ref_and_oblig; @@ -342,7 +342,7 @@ pub(super) fn specialization_graph_provider( unreachable!("converted to hard error above") } FutureCompatOverlapErrorKind::Issue33140 => { - lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS + ORDER_DEPENDENT_TRAIT_OBJECTS } }; tcx.struct_span_lint_hir( diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1b0b5fc4d078d..a97f33b31b7a3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -8,7 +8,7 @@ use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{self, Lint}; +use crate::lint::{maybe_lint_level_root, struct_lint_level, LintSource, LintStore}; use crate::middle; use crate::middle::cstore::CrateStoreDyn; use crate::middle::cstore::EncodedMetadata; @@ -61,6 +61,7 @@ use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal}; use rustc_errors::DiagnosticBuilder; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; +use rustc_session::lint::{Level, Lint}; use rustc_session::node_id::NodeMap; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{kw, sym, Symbol}; @@ -946,7 +947,7 @@ pub struct GlobalCtxt<'tcx> { pub sess: &'tcx Session, - pub lint_store: Lrc, + pub lint_store: Lrc, pub dep_graph: DepGraph, @@ -1115,7 +1116,7 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc, + lint_store: Lrc, local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, @@ -2551,21 +2552,21 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_goals(xs)) } - pub fn lint_hir>( + pub fn lint_hir( self, lint: &'static Lint, hir_id: HirId, - span: S, + span: impl Into, msg: &str, ) { self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit() } - pub fn lint_hir_note>( + pub fn lint_hir_note( self, lint: &'static Lint, hir_id: HirId, - span: S, + span: impl Into, msg: &str, note: &str, ) { @@ -2574,11 +2575,11 @@ impl<'tcx> TyCtxt<'tcx> { err.emit() } - pub fn lint_node_note>( + pub fn lint_node_note( self, lint: &'static Lint, id: hir::HirId, - span: S, + span: impl Into, msg: &str, note: &str, ) { @@ -2598,7 +2599,7 @@ impl<'tcx> TyCtxt<'tcx> { if id == bound { return bound; } - if lint::maybe_lint_level_root(self, id) { + if maybe_lint_level_root(self, id) { return id; } let next = self.hir().get_parent_node(id); @@ -2613,7 +2614,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (lint::Level, lint::LintSource) { + ) -> (Level, LintSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { @@ -2627,15 +2628,15 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn struct_span_lint_hir>( + pub fn struct_span_lint_hir( self, lint: &'static Lint, hir_id: HirId, - span: S, + span: impl Into, msg: &str, ) -> DiagnosticBuilder<'tcx> { let (level, src) = self.lint_level_at_node(lint, hir_id); - lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg) + struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg) } pub fn struct_lint_node( @@ -2645,7 +2646,7 @@ impl<'tcx> TyCtxt<'tcx> { msg: &str, ) -> DiagnosticBuilder<'tcx> { let (level, src) = self.lint_level_at_node(lint, id); - lint::struct_lint_level(self.sess, lint, level, src, None, msg) + struct_lint_level(self.sess, lint, level, src, None, msg) } pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec> { diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 6b272ab3d4a9b..1d41871bb33a9 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,7 +1,7 @@ use crate::dep_graph::{self, DepNode}; use crate::hir::exports::Export; use crate::infer::canonical::{self, Canonical}; -use crate::lint; +use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind}; use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary}; diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml index dced4a0d15b0c..2d45e28044495 100644 --- a/src/librustc_ast_passes/Cargo.toml +++ b/src/librustc_ast_passes/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" [dependencies] log = "0.4" rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors", package = "rustc_errors" } +rustc_errors = { path = "../librustc_errors" } rustc_error_codes = { path = "../librustc_error_codes" } rustc_feature = { path = "../librustc_feature" } rustc_parse = { path = "../librustc_parse" } From b93addba7add1f49249120b724023333db894055 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 03:03:48 +0100 Subject: [PATCH 02/14] move in_derive_expansion as Span method --- src/librustc/lint/mod.rs | 8 -------- src/librustc/middle/stability.rs | 5 ++--- src/librustc_span/lib.rs | 5 +++++ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 4afeb14494850..944868e79099b 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -494,11 +494,3 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { ExpnKind::Macro(..) => true, // definitely a plugin } } - -/// Returns `true` if `span` originates in a derive-macro's expansion. -pub fn in_derive_expansion(span: Span) -> bool { - if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind { - return true; - } - false -} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 93fc09b4a2ac9..1176ffc79d26d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -3,7 +3,6 @@ pub use self::StabilityLevel::*; -use crate::lint::in_derive_expansion; use crate::session::{DiagnosticMessageId, Session}; use crate::ty::{self, TyCtxt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -201,7 +200,7 @@ pub fn early_report_deprecation( lint: &'static Lint, span: Span, ) { - if in_derive_expansion(span) { + if span.in_derive_expansion() { return; } @@ -218,7 +217,7 @@ fn late_report_deprecation( def_id: DefId, hir_id: HirId, ) { - if in_derive_expansion(span) { + if span.in_derive_expansion() { return; } diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 8cca59df33846..f20cd6ae955f4 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -309,6 +309,11 @@ impl Span { self.ctxt() != SyntaxContext::root() } + /// Returns `true` if `span` originates in a derive-macro's expansion. + pub fn in_derive_expansion(self) -> bool { + matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) + } + #[inline] pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span { Span::new(lo, hi, SyntaxContext::root()) From c151782d76d1d664c1e55dd7ec2b44d3a18867c2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 03:28:45 +0100 Subject: [PATCH 03/14] reduce diversity in linting methods --- src/librustc/traits/object_safety.rs | 7 +++--- src/librustc/ty/context.rs | 26 -------------------- src/librustc_mir/transform/check_unsafety.rs | 10 ++++---- src/librustc_passes/liveness.rs | 17 +++++++------ 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index e4309dd28f4a1..ce57fb8110496 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -179,7 +179,7 @@ fn object_safety_violations_for_trait( { // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // It's also hard to get a use site span, so we use the method definition span. - tcx.lint_node_note( + tcx.struct_span_lint_hir( WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, *span, @@ -187,8 +187,9 @@ fn object_safety_violations_for_trait( "the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id) ), - &violation.error_msg(), - ); + ) + .note(&violation.error_msg()) + .emit(); false } else { true diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a97f33b31b7a3..eb65caf6fbe8f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2562,32 +2562,6 @@ impl<'tcx> TyCtxt<'tcx> { self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit() } - pub fn lint_hir_note( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - msg: &str, - note: &str, - ) { - let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg); - err.note(note); - err.emit() - } - - pub fn lint_node_note( - self, - lint: &'static Lint, - id: hir::HirId, - span: impl Into, - msg: &str, - note: &str, - ) { - let mut err = self.struct_span_lint_hir(lint, id, span.into(), msg); - err.note(note); - err.emit() - } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. pub fn maybe_lint_level_root_bounded( diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 02c54803842f0..3f342a6e6ca30 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -648,17 +648,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { tcx.unsafe_derive_on_repr_packed(impl_def_id); } else { - tcx.lint_node_note( + tcx.struct_span_lint_hir( SAFE_PACKED_BORROWS, lint_hir_id, source_info.span, &format!( - "{} is unsafe and requires unsafe function or block \ - (error E0133)", + "{} is unsafe and requires unsafe function or block (error E0133)", description ), - &details.as_str(), - ); + ) + .note(&details.as_str()) + .emit(); } } } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 0426f3fbea236..7718139f6e924 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -1513,13 +1513,16 @@ impl<'tcx> Liveness<'_, 'tcx> { if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; if is_assigned { - self.ir.tcx.lint_hir_note( - lint::builtin::UNUSED_VARIABLES, - hir_id, - spans, - &format!("variable `{}` is assigned to, but never used", name), - &format!("consider using `_{}` instead", name), - ); + self.ir + .tcx + .struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + hir_id, + spans, + &format!("variable `{}` is assigned to, but never used", name), + ) + .note(&format!("consider using `_{}` instead", name)) + .emit(); } else { let mut err = self.ir.tcx.struct_span_lint_hir( lint::builtin::UNUSED_VARIABLES, From 6f1a79cabe011c7487652e61130275a2940c47bc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 03:45:42 +0100 Subject: [PATCH 04/14] GlobalCtxt: Erase `LintStore` type. --- src/librustc/ty/context.rs | 10 +++++++--- src/librustc_lint/late.rs | 19 ++++++++++++------- src/librustc_lint/levels.rs | 5 +++-- src/librustc_lint/lib.rs | 1 + 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index eb65caf6fbe8f..15ef6d44d46da 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -8,7 +8,7 @@ use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{maybe_lint_level_root, struct_lint_level, LintSource, LintStore}; +use crate::lint::{maybe_lint_level_root, struct_lint_level, LintSource}; use crate::middle; use crate::middle::cstore::CrateStoreDyn; use crate::middle::cstore::EncodedMetadata; @@ -947,7 +947,11 @@ pub struct GlobalCtxt<'tcx> { pub sess: &'tcx Session, - pub lint_store: Lrc, + /// This only ever stores a `LintStore` but we don't want a dependency on that type here. + /// + /// FIXME(Centril): consider `dyn LintStoreMarker` once + /// we can upcast to `Any` for some additional type safety. + pub lint_store: Lrc, pub dep_graph: DepGraph, @@ -1116,7 +1120,7 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc, + lint_store: Lrc, local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, diff --git a/src/librustc_lint/late.rs b/src/librustc_lint/late.rs index d8e0274cf43b9..e3ab604d39881 100644 --- a/src/librustc_lint/late.rs +++ b/src/librustc_lint/late.rs @@ -15,8 +15,7 @@ //! for all lint attributes. use rustc::hir::map::Map; -use rustc::lint::LateContext; -use rustc::lint::{LateLintPass, LateLintPassObject}; +use rustc::lint::{LateContext, LateLintPass, LateLintPassObject, LintStore}; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; use rustc_hir as hir; @@ -31,6 +30,12 @@ use syntax::walk_list; use log::debug; use std::slice; +/// Extract the `LintStore` from the query context. +/// This function exists because we've erased `LintStore` as `dyn Any` in the context. +crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore { + tcx.lint_store.downcast_ref().unwrap() +} + macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); }) } @@ -356,7 +361,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( tables: &ty::TypeckTables::empty(None), param_env: ty::ParamEnv::empty(), access_levels, - lint_store: &tcx.lint_store, + lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(), generics: None, only_module: true, @@ -386,7 +391,7 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( late_lint_mod_pass(tcx, module_def_id, builtin_lints); let mut passes: Vec<_> = - tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); if !passes.is_empty() { late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); @@ -403,7 +408,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc tables: &ty::TypeckTables::empty(None), param_env: ty::ParamEnv::empty(), access_levels, - lint_store: &tcx.lint_store, + lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: hir::CRATE_HIR_ID, generics: None, only_module: false, @@ -424,7 +429,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc } fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { - let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::>(); + let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::>(); if !tcx.sess.opts.debugging_opts.no_interleave_lints { if !passes.is_empty() { @@ -443,7 +448,7 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b } let mut passes: Vec<_> = - tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); for pass in &mut passes { tcx.sess diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 3d3e57fe2bae3..a4910a02590d0 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -1,3 +1,4 @@ +use super::late::unerased_lint_store; use rustc::hir::map::Map; use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore}; use rustc::ty::query::Providers; @@ -11,11 +12,11 @@ pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId}; fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); - let store = &tcx.lint_store; + let store = unerased_lint_store(tcx); let mut builder = LintLevelMapBuilder { levels: LintLevelSets::builder(tcx.sess, false, &store), tcx: tcx, - store: store, + store, }; let krate = tcx.hir().krate(); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e708ded603b25..f62e9c466daee 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -14,6 +14,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(crate_visibility_modifier)] #![feature(nll)] #![recursion_limit = "256"] From 03bdfe9db3c7814e474413c4238f3eca7c2bf39a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 04:06:33 +0100 Subject: [PATCH 05/14] move logic to LintLevelsBuilder --- src/librustc/lint/context.rs | 4 +- src/librustc/lint/levels.rs | 80 +++++++++++++++--------------------- src/librustc_lint/levels.rs | 9 ++-- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 867eb5a193707..779077f1ff44d 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -17,7 +17,7 @@ use self::TargetLint::*; use crate::hir::map::definitions::{DefPathData, DisambiguatedDefPathData}; -use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; +use crate::lint::levels::LintLevelsBuilder; use crate::lint::{EarlyLintPassObject, LateLintPassObject}; use crate::middle::privacy::AccessLevels; use crate::middle::stability; @@ -674,7 +674,7 @@ impl<'a> EarlyContext<'a> { sess, krate, lint_store, - builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store), + builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store), buffered, } } diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index fdd2a8d0778e2..04028c03d4364 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -37,44 +37,8 @@ enum LintSet { } impl LintLevelSets { - pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets { - let mut me = LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }; - me.process_command_line(sess, lint_store); - return me; - } - - pub fn builder<'a>( - sess: &'a Session, - warn_about_weird_lints: bool, - store: &LintStore, - ) -> LintLevelsBuilder<'a> { - LintLevelsBuilder::new(sess, warn_about_weird_lints, LintLevelSets::new(sess, store)) - } - - fn process_command_line(&mut self, sess: &Session, store: &LintStore) { - let mut specs = FxHashMap::default(); - self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); - - for &(ref lint_name, level) in &sess.opts.lint_opts { - store.check_lint_name_cmdline(sess, &lint_name, level); - - // If the cap is less than this specified level, e.g., if we've got - // `--cap-lints allow` but we've also got `-D foo` then we ignore - // this specification as the lint cap will set it to allow anyway. - let level = cmp::min(level, self.lint_cap); - - let lint_flag_val = Symbol::intern(lint_name); - let ids = match store.find_lints(&lint_name) { - Ok(ids) => ids, - Err(_) => continue, // errors handled in check_lint_name_cmdline above - }; - for id in ids { - let src = LintSource::CommandLine(lint_flag_val); - specs.insert(id, (level, src)); - } - } - - self.list.push(LintSet::CommandLine { specs: specs }); + fn new() -> Self { + LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid } } fn get_lint_level( @@ -159,19 +123,43 @@ pub struct BuilderPush { } impl<'a> LintLevelsBuilder<'a> { - pub fn new( - sess: &'a Session, - warn_about_weird_lints: bool, - sets: LintLevelSets, - ) -> LintLevelsBuilder<'a> { - assert_eq!(sets.list.len(), 1); - LintLevelsBuilder { + pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { + let mut builder = LintLevelsBuilder { sess, - sets, + sets: LintLevelSets::new(), cur: 0, id_to_set: Default::default(), warn_about_weird_lints, + }; + builder.process_command_line(sess, store); + assert_eq!(builder.sets.list.len(), 1); + builder + } + + fn process_command_line(&mut self, sess: &Session, store: &LintStore) { + let mut specs = FxHashMap::default(); + self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); + + for &(ref lint_name, level) in &sess.opts.lint_opts { + store.check_lint_name_cmdline(sess, &lint_name, level); + + // If the cap is less than this specified level, e.g., if we've got + // `--cap-lints allow` but we've also got `-D foo` then we ignore + // this specification as the lint cap will set it to allow anyway. + let level = cmp::min(level, self.sets.lint_cap); + + let lint_flag_val = Symbol::intern(lint_name); + let ids = match store.find_lints(&lint_name) { + Ok(ids) => ids, + Err(_) => continue, // errors handled in check_lint_name_cmdline above + }; + for id in ids { + let src = LintSource::CommandLine(lint_flag_val); + specs.insert(id, (level, src)); + } } + + self.sets.list.push(LintSet::CommandLine { specs }); } /// Pushes a list of AST lint attributes onto this context. diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index a4910a02590d0..46ea04e5ccfca 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -1,6 +1,6 @@ use super::late::unerased_lint_store; use rustc::hir::map::Map; -use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore}; +use rustc::lint::{LintLevelMap, LintLevelsBuilder, LintStore}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_hir as hir; @@ -13,11 +13,8 @@ pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId}; fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); let store = unerased_lint_store(tcx); - let mut builder = LintLevelMapBuilder { - levels: LintLevelSets::builder(tcx.sess, false, &store), - tcx: tcx, - store, - }; + let levels = LintLevelsBuilder::new(tcx.sess, false, &store); + let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); let push = builder.levels.push(&krate.attrs, &store); From f577b44712f0cba0404482b3e44d24ceb5b54a9e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 05:20:28 +0100 Subject: [PATCH 06/14] move LintSource to levels --- src/librustc/lint/levels.rs | 39 ++++++++++++++++++++++++++----------- src/librustc/lint/mod.rs | 22 ++------------------- src/librustc/ty/context.rs | 6 +++--- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 04028c03d4364..d43bc57ea7a60 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -1,8 +1,8 @@ use std::cmp; use crate::ich::StableHashingContext; +use crate::lint; use crate::lint::context::{CheckLintNameResult, LintStore}; -use crate::lint::{self, LintSource}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -11,6 +11,7 @@ use rustc_session::lint::{builtin, Level, Lint, LintId}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; use syntax::ast; use syntax::attr; use syntax::print::pprust; @@ -18,6 +19,22 @@ use syntax::sess::feature_err; use rustc_error_codes::*; +/// How a lint level was set. +#[derive(Clone, Copy, PartialEq, Eq, HashStable)] +pub enum LintSource { + /// Lint is at the default level as declared + /// in rustc or a plugin. + Default, + + /// Lint level was set by an attribute. + Node(Symbol, Span, Option /* RFC 2383 reason */), + + /// Lint level was set by a command-line flag. + CommandLine(Symbol), +} + +pub type LevelSource = (Level, LintSource); + pub struct LintLevelSets { list: Vec, lint_cap: Level, @@ -27,27 +44,27 @@ enum LintSet { CommandLine { // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which // flag. - specs: FxHashMap, + specs: FxHashMap, }, Node { - specs: FxHashMap, + specs: FxHashMap, parent: u32, }, } impl LintLevelSets { - fn new() -> Self { + pub fn new() -> Self { LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid } } - fn get_lint_level( + pub fn get_lint_level( &self, lint: &'static Lint, idx: u32, - aux: Option<&FxHashMap>, + aux: Option<&FxHashMap>, sess: &Session, - ) -> (Level, LintSource) { + ) -> LevelSource { let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); // If `level` is none then we actually assume the default level for this @@ -59,7 +76,7 @@ impl LintLevelSets { // `allow(warnings)` in scope then we want to respect that instead. if level == Level::Warn { let (warnings_level, warnings_src) = - self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx, aux); + self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); if let Some(configured_warning_level) = warnings_level { if configured_warning_level != Level::Warn { level = configured_warning_level; @@ -79,11 +96,11 @@ impl LintLevelSets { return (level, src); } - fn get_lint_id_level( + pub fn get_lint_id_level( &self, id: LintId, mut idx: u32, - aux: Option<&FxHashMap>, + aux: Option<&FxHashMap>, ) -> (Option, LintSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { @@ -499,7 +516,7 @@ impl LintLevelMap { lint: &'static Lint, id: HirId, session: &Session, - ) -> Option<(Level, LintSource)> { + ) -> Option { self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session)) } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 944868e79099b..eefcb670d0e83 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -18,8 +18,8 @@ //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. +pub use self::levels::LintSource::{self, *}; pub use self::Level::*; -pub use self::LintSource::*; use crate::ty::TyCtxt; use rustc_data_structures::sync; @@ -29,7 +29,6 @@ use rustc_session::lint::builtin::HardwiredLints; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; -use rustc_span::symbol::Symbol; use rustc_span::Span; use syntax::ast; @@ -38,9 +37,8 @@ pub use crate::lint::context::{ LintContext, LintStore, }; -pub use rustc_session::lint::builtin; +pub use rustc_session::lint::{builtin, LintArray, LintPass}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId}; -pub use rustc_session::lint::{LintArray, LintPass}; #[macro_export] macro_rules! late_lint_methods { @@ -316,22 +314,6 @@ pub type EarlyLintPassObject = Box LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>; -/// How a lint level was set. -#[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { - /// Lint is at the default level as declared - /// in rustc or a plugin. - Default, - - /// Lint level was set by an attribute. - Node(ast::Name, Span, Option /* RFC 2383 reason */), - - /// Lint level was set by a command-line flag. - CommandLine(Symbol), -} - -pub type LevelSource = (Level, LintSource); - mod context; pub mod internal; mod levels; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 15ef6d44d46da..86f82c1304c48 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -20,9 +20,6 @@ use crate::mir::interpret::{Allocation, ConstValue, Scalar}; use crate::mir::{ interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, }; -use crate::session::config::CrateType; -use crate::session::config::{BorrowckMode, OutputFilenames}; -use crate::session::Session; use crate::traits; use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals}; use crate::ty::free_region_map::FreeRegionMap; @@ -49,6 +46,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE}; use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet}; +use rustc_session::config::CrateType; +use rustc_session::config::{BorrowckMode, OutputFilenames}; +use rustc_session::Session; use arena::SyncDroplessArena; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; From eee84fe3960f0bb79f8bf02577bf00aa44302e00 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 05:57:07 +0100 Subject: [PATCH 07/14] move struct_lint_level to levels.rs --- src/librustc/lint/levels.rs | 168 ++++++++++++++++++++++++++++++++++-- src/librustc/lint/mod.rs | 158 +-------------------------------- 2 files changed, 161 insertions(+), 165 deletions(-) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index d43bc57ea7a60..7e966a7491050 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -1,15 +1,15 @@ use std::cmp; use crate::ich::StableHashingContext; -use crate::lint; use crate::lint::context::{CheckLintNameResult, LintStore}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; use rustc_session::lint::{builtin, Level, Lint, LintId}; -use rustc_session::Session; -use rustc_span::source_map::MultiSpan; +use rustc_session::{DiagnosticMessageId, Session}; +use rustc_span::hygiene::MacroKind; +use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use syntax::ast; @@ -326,7 +326,7 @@ impl<'a> LintLevelsBuilder<'a> { Also `cfg_attr(cargo-clippy)` won't be necessary anymore", name ); - lint::struct_lint_level( + struct_lint_level( self.sess, lint, lvl, @@ -366,7 +366,7 @@ impl<'a> LintLevelsBuilder<'a> { let lint = builtin::RENAMED_AND_REMOVED_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); - let mut err = lint::struct_lint_level( + let mut err = struct_lint_level( self.sess, lint, level, @@ -389,7 +389,7 @@ impl<'a> LintLevelsBuilder<'a> { let (level, src) = self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); let msg = format!("unknown lint: `{}`", name); - let mut db = lint::struct_lint_level( + let mut db = struct_lint_level( self.sess, lint, level, @@ -480,7 +480,7 @@ impl<'a> LintLevelsBuilder<'a> { msg: &str, ) -> DiagnosticBuilder<'a> { let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess); - lint::struct_lint_level(self.sess, lint, level, src, span, msg) + struct_lint_level(self.sess, lint, level, src, span, msg) } /// Registers the ID provided with the current set of lints stored in @@ -553,3 +553,155 @@ impl<'a> HashStable> for LintLevelMap { }) } } + +pub fn struct_lint_level<'a>( + sess: &'a Session, + lint: &'static Lint, + level: Level, + src: LintSource, + span: Option, + msg: &str, +) -> DiagnosticBuilder<'a> { + let mut err = match (level, span) { + (Level::Allow, _) => return sess.diagnostic().struct_dummy(), + (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg), + (Level::Warn, None) => sess.struct_warn(msg), + (Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg), + (Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg), + }; + + // Check for future incompatibility lints and issue a stronger warning. + let lint_id = LintId::of(lint); + let future_incompatible = lint.future_incompatible; + + // If this code originates in a foreign macro, aka something that this crate + // did not itself author, then it's likely that there's nothing this crate + // can do about it. We probably want to skip the lint entirely. + if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { + // Any suggestions made here are likely to be incorrect, so anything we + // emit shouldn't be automatically fixed by rustfix. + err.allow_suggestions(false); + + // If this is a future incompatible lint it'll become a hard error, so + // we have to emit *something*. Also allow lints to whitelist themselves + // on a case-by-case basis for emission in a foreign macro. + if future_incompatible.is_none() && !lint.report_in_external_macro { + err.cancel(); + // Don't continue further, since we don't want to have + // `diag_span_note_once` called for a diagnostic that isn't emitted. + return err; + } + } + + let name = lint.name_lower(); + match src { + LintSource::Default => { + sess.diag_note_once( + &mut err, + DiagnosticMessageId::from(lint), + &format!("`#[{}({})]` on by default", level.as_str(), name), + ); + } + LintSource::CommandLine(lint_flag_val) => { + let flag = match level { + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Allow => panic!(), + }; + let hyphen_case_lint_name = name.replace("_", "-"); + if lint_flag_val.as_str() == name { + sess.diag_note_once( + &mut err, + DiagnosticMessageId::from(lint), + &format!( + "requested on the command line with `{} {}`", + flag, hyphen_case_lint_name + ), + ); + } else { + let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); + sess.diag_note_once( + &mut err, + DiagnosticMessageId::from(lint), + &format!( + "`{} {}` implied by `{} {}`", + flag, hyphen_case_lint_name, flag, hyphen_case_flag_val + ), + ); + } + } + LintSource::Node(lint_attr_name, src, reason) => { + if let Some(rationale) = reason { + err.note(&rationale.as_str()); + } + sess.diag_span_note_once( + &mut err, + DiagnosticMessageId::from(lint), + src, + "lint level defined here", + ); + if lint_attr_name.as_str() != name { + let level_str = level.as_str(); + sess.diag_note_once( + &mut err, + DiagnosticMessageId::from(lint), + &format!( + "`#[{}({})]` implied by `#[{}({})]`", + level_str, name, level_str, lint_attr_name + ), + ); + } + } + } + + err.code(DiagnosticId::Lint(name)); + + if let Some(future_incompatible) = future_incompatible { + const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ + it will become a hard error"; + + let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { + "once this method is added to the standard library, \ + the ambiguity may cause an error or change in behavior!" + .to_owned() + } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { + "this borrowing pattern was not meant to be accepted, \ + and may become a hard error in the future" + .to_owned() + } else if let Some(edition) = future_incompatible.edition { + format!("{} in the {} edition!", STANDARD_MESSAGE, edition) + } else { + format!("{} in a future release!", STANDARD_MESSAGE) + }; + let citation = format!("for more information, see {}", future_incompatible.reference); + err.warn(&explanation); + err.note(&citation); + } + + return err; +} + +/// Returns whether `span` originates in a foreign crate's external macro. +/// +/// This is used to test whether a lint should not even begin to figure out whether it should +/// be reported on the current node. +pub fn in_external_macro(sess: &Session, span: Span) -> bool { + let expn_data = span.ctxt().outer_expn_data(); + match expn_data.kind { + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::Macro(MacroKind::Bang, _) => { + if expn_data.def_site.is_dummy() { + // Dummy span for the `def_site` means it's an external macro. + return true; + } + match sess.source_map().span_to_snippet(expn_data.def_site) { + Ok(code) => !code.starts_with("macro_rules"), + // No snippet means external macro or compiler-builtin expansion. + Err(_) => true, + } + } + ExpnKind::Macro(..) => true, // definitely a plugin + } +} diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index eefcb670d0e83..371fa27cb2418 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -23,12 +23,8 @@ pub use self::Level::*; use crate::ty::TyCtxt; use rustc_data_structures::sync; -use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; -use rustc_session::{DiagnosticMessageId, Session}; -use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; use rustc_span::Span; use syntax::ast; @@ -318,161 +314,9 @@ mod context; pub mod internal; mod levels; -pub use self::levels::{LintLevelMap, LintLevelSets, LintLevelsBuilder}; - -pub fn struct_lint_level<'a>( - sess: &'a Session, - lint: &'static Lint, - level: Level, - src: LintSource, - span: Option, - msg: &str, -) -> DiagnosticBuilder<'a> { - let mut err = match (level, span) { - (Level::Allow, _) => return sess.diagnostic().struct_dummy(), - (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg), - (Level::Warn, None) => sess.struct_warn(msg), - (Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg), - (Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg), - }; - - // Check for future incompatibility lints and issue a stronger warning. - let lint_id = LintId::of(lint); - let future_incompatible = lint.future_incompatible; - - // If this code originates in a foreign macro, aka something that this crate - // did not itself author, then it's likely that there's nothing this crate - // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { - // Any suggestions made here are likely to be incorrect, so anything we - // emit shouldn't be automatically fixed by rustfix. - err.allow_suggestions(false); - - // If this is a future incompatible lint it'll become a hard error, so - // we have to emit *something*. Also allow lints to whitelist themselves - // on a case-by-case basis for emission in a foreign macro. - if future_incompatible.is_none() && !lint.report_in_external_macro { - err.cancel(); - // Don't continue further, since we don't want to have - // `diag_span_note_once` called for a diagnostic that isn't emitted. - return err; - } - } - - let name = lint.name_lower(); - match src { - LintSource::Default => { - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!("`#[{}({})]` on by default", level.as_str(), name), - ); - } - LintSource::CommandLine(lint_flag_val) => { - let flag = match level { - Level::Warn => "-W", - Level::Deny => "-D", - Level::Forbid => "-F", - Level::Allow => panic!(), - }; - let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str() == name { - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "requested on the command line with `{} {}`", - flag, hyphen_case_lint_name - ), - ); - } else { - let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "`{} {}` implied by `{} {}`", - flag, hyphen_case_lint_name, flag, hyphen_case_flag_val - ), - ); - } - } - LintSource::Node(lint_attr_name, src, reason) => { - if let Some(rationale) = reason { - err.note(&rationale.as_str()); - } - sess.diag_span_note_once( - &mut err, - DiagnosticMessageId::from(lint), - src, - "lint level defined here", - ); - if lint_attr_name.as_str() != name { - let level_str = level.as_str(); - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "`#[{}({})]` implied by `#[{}({})]`", - level_str, name, level_str, lint_attr_name - ), - ); - } - } - } - - err.code(DiagnosticId::Lint(name)); - - if let Some(future_incompatible) = future_incompatible { - const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error"; - - let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { - "once this method is added to the standard library, \ - the ambiguity may cause an error or change in behavior!" - .to_owned() - } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { - "this borrowing pattern was not meant to be accepted, \ - and may become a hard error in the future" - .to_owned() - } else if let Some(edition) = future_incompatible.edition { - format!("{} in the {} edition!", STANDARD_MESSAGE, edition) - } else { - format!("{} in a future release!", STANDARD_MESSAGE) - }; - let citation = format!("for more information, see {}", future_incompatible.reference); - err.warn(&explanation); - err.note(&citation); - } - - return err; -} +pub use self::levels::{struct_lint_level, LintLevelMap, LintLevelSets, LintLevelsBuilder}; pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { let attrs = tcx.hir().attrs(id); attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) } - -/// Returns whether `span` originates in a foreign crate's external macro. -/// -/// This is used to test whether a lint should not even begin to figure out whether it should -/// be reported on the current node. -pub fn in_external_macro(sess: &Session, span: Span) -> bool { - let expn_data = span.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::Macro(MacroKind::Bang, _) => { - if expn_data.def_site.is_dummy() { - // Dummy span for the `def_site` means it's an external macro. - return true; - } - match sess.source_map().span_to_snippet(expn_data.def_site) { - Ok(code) => !code.starts_with("macro_rules"), - // No snippet means external macro or compiler-builtin expansion. - Err(_) => true, - } - } - ExpnKind::Macro(..) => true, // definitely a plugin - } -} From 16bf2783b5cd5f0a6155094f885890f4c0834477 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 06:08:07 +0100 Subject: [PATCH 08/14] inline maybe_lint_level_root --- src/librustc/lint/mod.rs | 6 ------ src/librustc/ty/context.rs | 14 ++++++-------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 371fa27cb2418..6eec77d1d9075 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -21,7 +21,6 @@ pub use self::levels::LintSource::{self, *}; pub use self::Level::*; -use crate::ty::TyCtxt; use rustc_data_structures::sync; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; @@ -315,8 +314,3 @@ pub mod internal; mod levels; pub use self::levels::{struct_lint_level, LintLevelMap, LintLevelSets, LintLevelsBuilder}; - -pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - let attrs = tcx.hir().attrs(id); - attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 86f82c1304c48..c28631b982577 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -8,7 +8,7 @@ use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{maybe_lint_level_root, struct_lint_level, LintSource}; +use crate::lint::{struct_lint_level, LintSource}; use crate::middle; use crate::middle::cstore::CrateStoreDyn; use crate::middle::cstore::EncodedMetadata; @@ -2568,19 +2568,17 @@ impl<'tcx> TyCtxt<'tcx> { /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. - pub fn maybe_lint_level_root_bounded( - self, - mut id: hir::HirId, - bound: hir::HirId, - ) -> hir::HirId { + pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { + let hir = self.hir(); loop { if id == bound { return bound; } - if maybe_lint_level_root(self, id) { + + if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) { return id; } - let next = self.hir().get_parent_node(id); + let next = hir.get_parent_node(id); if next == id { bug!("lint traversal reached the root of the crate"); } From 03dfa642d9080a12e491681097806eb4207d19dc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 06:42:42 +0100 Subject: [PATCH 09/14] lints: promote levels.rs to lint.rs & extract passes.rs --- src/librustc/{lint/levels.rs => lint.rs} | 12 ++++++++++-- src/librustc/lint/context.rs | 4 ++-- src/librustc/lint/internal.rs | 3 ++- src/librustc/lint/{mod.rs => passes.rs} | 8 +------- src/librustc/mir/interpret/error.rs | 2 +- src/librustc_lint/array_into_iter.rs | 3 ++- src/librustc_passes/dead.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/lib.rs | 1 + 9 files changed, 21 insertions(+), 16 deletions(-) rename src/librustc/{lint/levels.rs => lint.rs} (98%) rename src/librustc/lint/{mod.rs => passes.rs} (98%) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint.rs similarity index 98% rename from src/librustc/lint/levels.rs rename to src/librustc/lint.rs index 7e966a7491050..c4332fa0c6346 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint.rs @@ -1,12 +1,12 @@ use std::cmp; use crate::ich::StableHashingContext; -use crate::lint::context::{CheckLintNameResult, LintStore}; +use crate::lint::context::CheckLintNameResult; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass}; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; @@ -19,6 +19,14 @@ use syntax::sess::feature_err; use rustc_error_codes::*; +mod context; +pub mod internal; +mod passes; + +pub use context::add_elided_lifetime_in_path_suggestion; +pub use context::{EarlyContext, LateContext, LintContext, LintStore}; +pub use passes::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}; + /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] pub enum LintSource { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 779077f1ff44d..702d707346bd8 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -17,8 +17,8 @@ use self::TargetLint::*; use crate::hir::map::definitions::{DefPathData, DisambiguatedDefPathData}; -use crate::lint::levels::LintLevelsBuilder; -use crate::lint::{EarlyLintPassObject, LateLintPassObject}; +use crate::lint::passes::{EarlyLintPassObject, LateLintPassObject}; +use crate::lint::LintLevelsBuilder; use crate::middle::privacy::AccessLevels; use crate::middle::stability; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index 30679226b9b71..33282a7291eb9 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -1,7 +1,8 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use crate::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use crate::lint::context::{EarlyContext, LateContext, LintContext}; +use crate::lint::passes::{EarlyLintPass, LateLintPass}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/passes.rs similarity index 98% rename from src/librustc/lint/mod.rs rename to src/librustc/lint/passes.rs index 6eec77d1d9075..41671ccc6c0fc 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/passes.rs @@ -18,8 +18,8 @@ //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. -pub use self::levels::LintSource::{self, *}; pub use self::Level::*; +pub use crate::lint::LintSource::{self, *}; use rustc_data_structures::sync; use rustc_hir as hir; @@ -308,9 +308,3 @@ macro_rules! declare_combined_early_lint_pass { pub type EarlyLintPassObject = Box; pub type LateLintPassObject = Box LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>; - -mod context; -pub mod internal; -mod levels; - -pub use self::levels::{struct_lint_level, LintLevelMap, LintLevelSets, LintLevelsBuilder}; diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index ed61534d54519..8643bd63d8cba 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -154,7 +154,7 @@ impl<'tcx> ConstEvalErr<'tcx> { .next() .unwrap_or(lint_root); tcx.struct_span_lint_hir( - crate::rustc::lint::builtin::CONST_ERR, + rustc_session::lint::builtin::CONST_ERR, hir_id, tcx.span, message, diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs index 19d1052d1b243..7f053f9de2953 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/src/librustc_lint/array_into_iter.rs @@ -1,8 +1,9 @@ -use rustc::lint::{FutureIncompatibleInfo, LateContext, LateLintPass, LintContext}; +use rustc::lint::{LateContext, LateLintPass, LintContext}; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::symbol::sym; declare_lint! { diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs index f626a5f8cb0d1..f2778b2aa6bcd 100644 --- a/src/librustc_passes/dead.rs +++ b/src/librustc_passes/dead.rs @@ -3,7 +3,6 @@ // from live codes are live, and everything else is dead. use rustc::hir::map::Map; -use rustc::lint; use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::middle::privacy; use rustc::ty::{self, DefIdTree, TyCtxt}; @@ -14,6 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; +use rustc_session::lint; use rustc_span; use rustc_span::symbol::sym; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3cda1b3be75f1..61a7bc765bcf2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc::lint; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; use rustc::session::config::ErrorOutputType; @@ -14,6 +13,7 @@ use rustc_hir::HirId; use rustc_interface::interface; use rustc_lint; use rustc_resolve as resolve; +use rustc_session::lint; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b15dae452ff05..032a5c83d1724 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -36,6 +36,7 @@ extern crate rustc_metadata; extern crate rustc_mir; extern crate rustc_parse; extern crate rustc_resolve; +extern crate rustc_session; extern crate rustc_span as rustc_span; extern crate rustc_target; extern crate rustc_typeck; From 8c12c424e28beb9bf69df8ca0f68096d8b9a6a21 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 06:49:49 +0100 Subject: [PATCH 10/14] {rustc::lint -> rustc_lint}::internal --- Cargo.lock | 1 + src/librustc/lint.rs | 1 - src/librustc_lint/Cargo.toml | 1 + src/{librustc/lint => librustc_lint}/internal.rs | 4 ++-- src/librustc_lint/lib.rs | 3 ++- 5 files changed, 6 insertions(+), 4 deletions(-) rename src/{librustc/lint => librustc_lint}/internal.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 54ad60e71506b..214114240aff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3663,6 +3663,7 @@ dependencies = [ "log", "rustc", "rustc_data_structures", + "rustc_error_codes", "rustc_errors", "rustc_feature", "rustc_hir", diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index c4332fa0c6346..b85982ac3ffce 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -20,7 +20,6 @@ use syntax::sess::feature_err; use rustc_error_codes::*; mod context; -pub mod internal; mod passes; pub use context::add_elided_lifetime_in_path_suggestion; diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 7e23e70577975..abf9f96e6475b 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -13,6 +13,7 @@ log = "0.4" unicode-security = "0.0.2" rustc = { path = "../librustc" } rustc_errors = { path = "../librustc_errors" } +rustc_error_codes = { path = "../librustc_error_codes" } rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } diff --git a/src/librustc/lint/internal.rs b/src/librustc_lint/internal.rs similarity index 98% rename from src/librustc/lint/internal.rs rename to src/librustc_lint/internal.rs index 33282a7291eb9..30417bf5a24fc 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc_lint/internal.rs @@ -1,8 +1,8 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use crate::lint::context::{EarlyContext, LateContext, LintContext}; -use crate::lint::passes::{EarlyLintPass, LateLintPass}; +use crate::lint::{EarlyContext, LateContext, LintContext}; +use crate::lint::{EarlyLintPass, LateLintPass}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index f62e9c466daee..e11472e1136f7 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -26,6 +26,7 @@ extern crate rustc_session; mod array_into_iter; pub mod builtin; mod early; +mod internal; mod late; mod levels; mod non_ascii_idents; @@ -53,10 +54,10 @@ use lint::LintId; use array_into_iter::ArrayIntoIter; use builtin::*; +use internal::*; use non_ascii_idents::*; use nonstandard_style::*; use redundant_semicolon::*; -use rustc::lint::internal::*; use types::*; use unused::*; From f58db203623b89e6c9e68d4b9ccb000031825cc4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 07:52:01 +0100 Subject: [PATCH 11/14] move rustc::lint::{context, passes} to rustc_lint. Also do some cleanup of the interface. --- Cargo.lock | 1 + src/librustc/lib.rs | 2 - src/librustc/lint.rs | 443 ++---------------- src/librustc_ast_lowering/lib.rs | 3 +- src/librustc_driver/lib.rs | 13 +- src/librustc_interface/interface.rs | 5 +- src/librustc_interface/passes.rs | 13 +- src/librustc_interface/queries.rs | 5 +- src/librustc_lint/array_into_iter.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- .../lint => librustc_lint}/context.rs | 59 +-- src/librustc_lint/early.rs | 9 +- src/librustc_lint/internal.rs | 3 +- src/librustc_lint/late.rs | 4 +- src/librustc_lint/levels.rs | 391 +++++++++++++++- src/librustc_lint/lib.rs | 32 +- src/librustc_lint/non_ascii_idents.rs | 2 +- src/librustc_lint/nonstandard_style.rs | 2 +- .../lint => librustc_lint}/passes.rs | 14 +- src/librustc_lint/redundant_semicolon.rs | 2 +- src/librustc_lint/types.rs | 2 +- src/librustc_lint/unused.rs | 4 +- src/librustc_plugin_impl/Cargo.toml | 1 + src/librustc_plugin_impl/lib.rs | 2 +- 24 files changed, 505 insertions(+), 513 deletions(-) rename src/{librustc/lint => librustc_lint}/context.rs (93%) rename src/{librustc/lint => librustc_lint}/passes.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index 214114240aff9..0008a4a361531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3789,6 +3789,7 @@ dependencies = [ "rustc_error_codes", "rustc_errors", "rustc_hir", + "rustc_lint", "rustc_metadata", "rustc_span", "syntax", diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index cf424ffe7b293..ef22c6621ae2c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -72,8 +72,6 @@ extern crate rustc_data_structures; #[macro_use] extern crate log; #[macro_use] -extern crate syntax; -#[macro_use] extern crate smallvec; #[cfg(test)] diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index b85982ac3ffce..2ed6cd5283b10 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -1,30 +1,15 @@ use std::cmp; use crate::ich::StableHashingContext; -use crate::lint::context::CheckLintNameResult; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass}; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use syntax::ast; -use syntax::attr; -use syntax::print::pprust; -use syntax::sess::feature_err; - -use rustc_error_codes::*; - -mod context; -mod passes; - -pub use context::add_elided_lifetime_in_path_suggestion; -pub use context::{EarlyContext, LateContext, LintContext, LintStore}; -pub use passes::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}; +use rustc_span::{Span, Symbol}; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] @@ -43,11 +28,11 @@ pub enum LintSource { pub type LevelSource = (Level, LintSource); pub struct LintLevelSets { - list: Vec, - lint_cap: Level, + pub list: Vec, + pub lint_cap: Level, } -enum LintSet { +pub enum LintSet { CommandLine { // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which // flag. @@ -133,381 +118,9 @@ impl LintLevelSets { } } -pub struct LintLevelsBuilder<'a> { - sess: &'a Session, - sets: LintLevelSets, - id_to_set: FxHashMap, - cur: u32, - warn_about_weird_lints: bool, -} - -pub struct BuilderPush { - prev: u32, - pub changed: bool, -} - -impl<'a> LintLevelsBuilder<'a> { - pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { - let mut builder = LintLevelsBuilder { - sess, - sets: LintLevelSets::new(), - cur: 0, - id_to_set: Default::default(), - warn_about_weird_lints, - }; - builder.process_command_line(sess, store); - assert_eq!(builder.sets.list.len(), 1); - builder - } - - fn process_command_line(&mut self, sess: &Session, store: &LintStore) { - let mut specs = FxHashMap::default(); - self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); - - for &(ref lint_name, level) in &sess.opts.lint_opts { - store.check_lint_name_cmdline(sess, &lint_name, level); - - // If the cap is less than this specified level, e.g., if we've got - // `--cap-lints allow` but we've also got `-D foo` then we ignore - // this specification as the lint cap will set it to allow anyway. - let level = cmp::min(level, self.sets.lint_cap); - - let lint_flag_val = Symbol::intern(lint_name); - let ids = match store.find_lints(&lint_name) { - Ok(ids) => ids, - Err(_) => continue, // errors handled in check_lint_name_cmdline above - }; - for id in ids { - let src = LintSource::CommandLine(lint_flag_val); - specs.insert(id, (level, src)); - } - } - - self.sets.list.push(LintSet::CommandLine { specs }); - } - - /// Pushes a list of AST lint attributes onto this context. - /// - /// This function will return a `BuilderPush` object which should be passed - /// to `pop` when this scope for the attributes provided is exited. - /// - /// This function will perform a number of tasks: - /// - /// * It'll validate all lint-related attributes in `attrs` - /// * It'll mark all lint-related attributes as used - /// * Lint levels will be updated based on the attributes provided - /// * Lint attributes are validated, e.g., a #[forbid] can't be switched to - /// #[allow] - /// - /// Don't forget to call `pop`! - pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { - let mut specs = FxHashMap::default(); - let sess = self.sess; - let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); - for attr in attrs { - let level = match Level::from_symbol(attr.name_or_empty()) { - None => continue, - Some(lvl) => lvl, - }; - - let meta = unwrap_or!(attr.meta(), continue); - attr::mark_used(attr); - - let mut metas = unwrap_or!(meta.meta_item_list(), continue); - - if metas.is_empty() { - // FIXME (#55112): issue unused-attributes lint for `#[level()]` - continue; - } - - // Before processing the lint names, look for a reason (RFC 2383) - // at the end. - let mut reason = None; - let tail_li = &metas[metas.len() - 1]; - if let Some(item) = tail_li.meta_item() { - match item.kind { - ast::MetaItemKind::Word => {} // actual lint names handled later - ast::MetaItemKind::NameValue(ref name_value) => { - if item.path == sym::reason { - // found reason, reslice meta list to exclude it - metas = &metas[0..metas.len() - 1]; - // FIXME (#55112): issue unused-attributes lint if we thereby - // don't have any lint names (`#[level(reason = "foo")]`) - if let ast::LitKind::Str(rationale, _) = name_value.kind { - if !self.sess.features_untracked().lint_reasons { - feature_err( - &self.sess.parse_sess, - sym::lint_reasons, - item.span, - "lint reasons are experimental", - ) - .emit(); - } - reason = Some(rationale); - } else { - bad_attr(name_value.span) - .span_label(name_value.span, "reason must be a string literal") - .emit(); - } - } else { - bad_attr(item.span) - .span_label(item.span, "bad attribute argument") - .emit(); - } - } - ast::MetaItemKind::List(_) => { - bad_attr(item.span).span_label(item.span, "bad attribute argument").emit(); - } - } - } - - for li in metas { - let meta_item = match li.meta_item() { - Some(meta_item) if meta_item.is_word() => meta_item, - _ => { - let sp = li.span(); - let mut err = bad_attr(sp); - let mut add_label = true; - if let Some(item) = li.meta_item() { - if let ast::MetaItemKind::NameValue(_) = item.kind { - if item.path == sym::reason { - err.span_label(sp, "reason in lint attribute must come last"); - add_label = false; - } - } - } - if add_label { - err.span_label(sp, "bad attribute argument"); - } - err.emit(); - continue; - } - }; - let tool_name = if meta_item.path.segments.len() > 1 { - let tool_ident = meta_item.path.segments[0].ident; - if !attr::is_known_lint_tool(tool_ident) { - struct_span_err!( - sess, - tool_ident.span, - E0710, - "an unknown tool name found in scoped lint: `{}`", - pprust::path_to_string(&meta_item.path), - ) - .emit(); - continue; - } - - Some(tool_ident.name) - } else { - None - }; - let name = meta_item.path.segments.last().expect("empty lint name").ident.name; - match store.check_lint_name(&name.as_str(), tool_name) { - CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span(), reason); - for id in ids { - specs.insert(*id, (level, src)); - } - } - - CheckLintNameResult::Tool(result) => { - match result { - Ok(ids) => { - let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node( - Symbol::intern(complete_name), - li.span(), - reason, - ); - for id in ids { - specs.insert(*id, (level, src)); - } - } - Err((Some(ids), new_lint_name)) => { - let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (lvl, src) = - self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); - let msg = format!( - "lint name `{}` is deprecated \ - and may not have an effect in the future. \ - Also `cfg_attr(cargo-clippy)` won't be necessary anymore", - name - ); - struct_lint_level( - self.sess, - lint, - lvl, - src, - Some(li.span().into()), - &msg, - ) - .span_suggestion( - li.span(), - "change it to", - new_lint_name.to_string(), - Applicability::MachineApplicable, - ) - .emit(); - - let src = LintSource::Node( - Symbol::intern(&new_lint_name), - li.span(), - reason, - ); - for id in ids { - specs.insert(*id, (level, src)); - } - } - Err((None, _)) => { - // If Tool(Err(None, _)) is returned, then either the lint does not - // exist in the tool or the code was not compiled with the tool and - // therefore the lint was never added to the `LintStore`. To detect - // this is the responsibility of the lint tool. - } - } - } - - _ if !self.warn_about_weird_lints => {} - - CheckLintNameResult::Warning(msg, renamed) => { - let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (level, src) = - self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); - let mut err = struct_lint_level( - self.sess, - lint, - level, - src, - Some(li.span().into()), - &msg, - ); - if let Some(new_name) = renamed { - err.span_suggestion( - li.span(), - "use the new name", - new_name, - Applicability::MachineApplicable, - ); - } - err.emit(); - } - CheckLintNameResult::NoLint(suggestion) => { - let lint = builtin::UNKNOWN_LINTS; - let (level, src) = - self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); - let msg = format!("unknown lint: `{}`", name); - let mut db = struct_lint_level( - self.sess, - lint, - level, - src, - Some(li.span().into()), - &msg, - ); - - if let Some(suggestion) = suggestion { - db.span_suggestion( - li.span(), - "did you mean", - suggestion.to_string(), - Applicability::MachineApplicable, - ); - } - - db.emit(); - } - } - } - } - - for (id, &(level, ref src)) in specs.iter() { - if level == Level::Forbid { - continue; - } - let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) { - (Some(Level::Forbid), src) => src, - _ => continue, - }; - let forbidden_lint_name = match forbid_src { - LintSource::Default => id.to_string(), - LintSource::Node(name, _, _) => name.to_string(), - LintSource::CommandLine(name) => name.to_string(), - }; - let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), - _ => continue, - }; - let mut diag_builder = struct_span_err!( - self.sess, - lint_attr_span, - E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), - lint_attr_name, - forbidden_lint_name - ); - diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); - match forbid_src { - LintSource::Default => {} - LintSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag_builder.note(&rationale.as_str()); - } - } - LintSource::CommandLine(_) => { - diag_builder.note("`forbid` lint level was set on command line"); - } - } - diag_builder.emit(); - // don't set a separate error for every lint in the group - break; - } - - let prev = self.cur; - if specs.len() > 0 { - self.cur = self.sets.list.len() as u32; - self.sets.list.push(LintSet::Node { specs: specs, parent: prev }); - } - - BuilderPush { prev: prev, changed: prev != self.cur } - } - - /// Called after `push` when the scope of a set of attributes are exited. - pub fn pop(&mut self, push: BuilderPush) { - self.cur = push.prev; - } - - /// Used to emit a lint-related diagnostic based on the current state of - /// this lint context. - pub fn struct_lint( - &self, - lint: &'static Lint, - span: Option, - msg: &str, - ) -> DiagnosticBuilder<'a> { - let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess); - struct_lint_level(self.sess, lint, level, src, span, msg) - } - - /// Registers the ID provided with the current set of lints stored in - /// this context. - pub fn register_id(&mut self, id: HirId) { - self.id_to_set.insert(id, self.cur); - } - - pub fn build(self) -> LintLevelSets { - self.sets - } - - pub fn build_map(self) -> LintLevelMap { - LintLevelMap { sets: self.sets, id_to_set: self.id_to_set } - } -} - pub struct LintLevelMap { - sets: LintLevelSets, - id_to_set: FxHashMap, + pub sets: LintLevelSets, + pub id_to_set: FxHashMap, } impl LintLevelMap { @@ -712,3 +325,45 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { ExpnKind::Macro(..) => true, // definitely a plugin } } + +pub 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` 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{}", pluralize!(n)), + suggestion, + Applicability::MachineApplicable, + ); +} diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 58b8e8a089ad3..d30d0bd8345ff 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -37,7 +37,6 @@ use rustc::arena::Arena; use rustc::dep_graph::DepGraph; use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions}; use rustc::hir::map::Map; -use rustc::lint::builtin; use rustc::{bug, span_bug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; @@ -51,7 +50,7 @@ use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::IndexVec; use rustc_session::config::nightly_options; -use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::lint::{builtin, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::node_id::NodeMap; use rustc_session::Session; use rustc_span::hygiene::ExpnId; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 3d31f240a34e0..072b85d716d74 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -23,9 +23,7 @@ extern crate lazy_static; pub extern crate rustc_plugin_impl as plugin; -//use rustc_resolve as resolve; -use rustc::lint; -use rustc::lint::Lint; +use rustc::lint::{Lint, LintId}; use rustc::middle::cstore::MetadataLoader; use rustc::session::config::nightly_options; use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest}; @@ -41,6 +39,7 @@ use rustc_feature::{find_gated_cfg, UnstableFeatures}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::util::get_builtin_codegen_backend; use rustc_interface::{interface, Queries}; +use rustc_lint::LintStore; use rustc_metadata::locator; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; @@ -811,7 +810,7 @@ the command line flag directly. ); } -fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) { +fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) { println!( " Available lint options: @@ -832,8 +831,8 @@ Available lint options: } fn sort_lint_groups( - lints: Vec<(&'static str, Vec, bool)>, - ) -> Vec<(&'static str, Vec)> { + lints: Vec<(&'static str, Vec, bool)>, + ) -> Vec<(&'static str, Vec)> { let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); lints.sort_by_key(|l| l.0); lints @@ -892,7 +891,7 @@ Available lint options: println!(" {} {}", padded("----"), "---------"); println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings"); - let print_lint_groups = |lints: Vec<(&'static str, Vec)>| { + let print_lint_groups = |lints: Vec<(&'static str, Vec)>| { for (name, to) in lints { let name = name.to_lowercase().replace("_", "-"); let desc = to diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index d00875f6fee88..9cd9eb66cf6c1 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::OnDrop; use rustc_errors::registry::Registry; +use rustc_lint::LintStore; use rustc_parse::new_parser_from_source_str; use rustc_span::edition; use rustc_span::source_map::{FileLoader, FileName, SourceMap}; @@ -36,7 +37,7 @@ pub struct Compiler { pub(crate) output_dir: Option, pub(crate) output_file: Option, pub(crate) crate_name: Option, - pub(crate) register_lints: Option>, + pub(crate) register_lints: Option>, pub(crate) override_queries: Option, &mut ty::query::Providers<'_>)>, } @@ -136,7 +137,7 @@ pub struct Config { /// /// Note that if you find a Some here you probably want to call that function in the new /// function being registered. - pub register_lints: Option>, + pub register_lints: Option>, /// This is a callback from the driver that is called just after we have populated /// the list of queries. diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 9119466cbc048..67f9819f3314d 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -27,6 +27,7 @@ use rustc_errors::PResult; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental; +use rustc_lint::LintStore; use rustc_mir as mir; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; @@ -100,7 +101,7 @@ declare_box_region_type!( /// Returns `None` if we're aborting after handling -W help. pub fn configure_and_expand( sess: Lrc, - lint_store: Lrc, + lint_store: Lrc, metadata_loader: Box, krate: ast::Crate, crate_name: &str, @@ -150,10 +151,10 @@ impl BoxedResolver { pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, - register_lints: impl Fn(&Session, &mut lint::LintStore), + register_lints: impl Fn(&Session, &mut LintStore), mut krate: ast::Crate, crate_name: &str, -) -> Result<(ast::Crate, Lrc)> { +) -> Result<(ast::Crate, Lrc)> { krate = sess.time("attributes_injection", || { rustc_builtin_macros::cmdline_attrs::inject( krate, @@ -214,7 +215,7 @@ pub fn register_plugins<'a>( fn configure_and_expand_inner<'a>( sess: &'a Session, - lint_store: &'a lint::LintStore, + lint_store: &'a LintStore, mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, @@ -420,7 +421,7 @@ fn configure_and_expand_inner<'a>( pub fn lower_to_hir<'res, 'tcx>( sess: &'tcx Session, - lint_store: &lint::LintStore, + lint_store: &LintStore, resolver: &'res mut Resolver<'_>, dep_graph: &'res DepGraph, krate: &'res ast::Crate, @@ -705,7 +706,7 @@ impl<'tcx> QueryContext<'tcx> { pub fn create_global_ctxt<'tcx>( compiler: &'tcx Compiler, - lint_store: Lrc, + lint_store: Lrc, hir_forest: &'tcx map::Forest<'tcx>, mut resolver_outputs: ResolverOutputs, outputs: OutputFilenames, diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 7de1c36ce4b2e..bd9717d3f3d02 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -4,8 +4,6 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc::arena::Arena; use rustc::dep_graph::DepGraph; use rustc::hir::map; -use rustc::lint; -use rustc::lint::LintStore; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::session::Session; use rustc::ty::steal::Steal; @@ -15,6 +13,7 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::sync::{Lrc, Once, WorkerLocal}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_incremental::DepGraphFuture; +use rustc_lint::LintStore; use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::mem; @@ -133,7 +132,7 @@ impl<'tcx> Queries<'tcx> { let crate_name = self.crate_name()?.peek().clone(); let krate = self.parse()?.take(); - let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {}; + let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; let result = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs index 7f053f9de2953..fb11b6771e9ca 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/src/librustc_lint/array_into_iter.rs @@ -1,4 +1,4 @@ -use rustc::lint::{LateContext, LateLintPass, LintContext}; +use crate::{LateContext, LateLintPass, LintContext}; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment}; use rustc_errors::Applicability; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index befeb84e57c9c..15a8332a28492 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -21,8 +21,8 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. +use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::hir::map::Map; -use rustc::lint::{self, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::traits::misc::can_type_implement_copy; use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; @@ -51,7 +51,7 @@ use log::debug; use std::fmt::Write; // hardwired lints from librustc -pub use lint::builtin::*; +pub use rustc_session::lint::builtin::*; declare_lint! { WHILE_TRUE, diff --git a/src/librustc/lint/context.rs b/src/librustc_lint/context.rs similarity index 93% rename from src/librustc/lint/context.rs rename to src/librustc_lint/context.rs index 702d707346bd8..2b514c301f2a3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc_lint/context.rs @@ -16,17 +16,18 @@ use self::TargetLint::*; -use crate::hir::map::definitions::{DefPathData, DisambiguatedDefPathData}; -use crate::lint::passes::{EarlyLintPassObject, LateLintPassObject}; -use crate::lint::LintLevelsBuilder; -use crate::middle::privacy::AccessLevels; -use crate::middle::stability; -use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; -use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; +use crate::levels::LintLevelsBuilder; +use crate::passes::{EarlyLintPassObject, LateLintPassObject}; +use rustc::hir::map::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc::lint::add_elided_lifetime_in_path_suggestion; +use rustc::middle::privacy::AccessLevels; +use rustc::middle::stability; +use rustc::ty::layout::{LayoutError, LayoutOf, TyLayout}; +use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_error_codes::*; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -467,48 +468,6 @@ impl LintPassObject for EarlyLintPassObject {} impl LintPassObject for LateLintPassObject {} -pub 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` 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{}", pluralize!(n)), - suggestion, - Applicability::MachineApplicable, - ); -} - pub trait LintContext: Sized { type PassObject: LintPassObject; diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 9a90171985158..490114b2d4d2a 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -14,10 +14,9 @@ //! upon. As the ast is traversed, this keeps track of the current lint level //! for all lint attributes. -use rustc::lint::{EarlyContext, LintStore}; -use rustc::lint::{EarlyLintPass, EarlyLintPassObject}; -use rustc::lint::{LintContext, LintPass}; -use rustc_session::lint::LintBuffer; +use crate::context::{EarlyContext, LintContext, LintStore}; +use crate::passes::{EarlyLintPass, EarlyLintPassObject}; +use rustc_session::lint::{LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::Span; use syntax::ast; @@ -291,7 +290,7 @@ macro_rules! early_lint_pass_impl { ) } -early_lint_methods!(early_lint_pass_impl, []); +crate::early_lint_methods!(early_lint_pass_impl, []); fn early_lint_crate( sess: &Session, diff --git a/src/librustc_lint/internal.rs b/src/librustc_lint/internal.rs index 30417bf5a24fc..2f8393bd906c0 100644 --- a/src/librustc_lint/internal.rs +++ b/src/librustc_lint/internal.rs @@ -1,8 +1,7 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use crate::lint::{EarlyContext, LateContext, LintContext}; -use crate::lint::{EarlyLintPass, LateLintPass}; +use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; diff --git a/src/librustc_lint/late.rs b/src/librustc_lint/late.rs index e3ab604d39881..eb5f89c9507d3 100644 --- a/src/librustc_lint/late.rs +++ b/src/librustc_lint/late.rs @@ -14,8 +14,8 @@ //! upon. As the ast is traversed, this keeps track of the current lint level //! for all lint attributes. +use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc::hir::map::Map; -use rustc::lint::{LateContext, LateLintPass, LateLintPassObject, LintStore}; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; use rustc_hir as hir; @@ -347,7 +347,7 @@ macro_rules! late_lint_pass_impl { ) } -late_lint_methods!(late_lint_pass_impl, [], ['tcx]); +crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]); fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( tcx: TyCtxt<'tcx>, diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 46ea04e5ccfca..bbc3e57f5dd01 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -1,14 +1,27 @@ -use super::late::unerased_lint_store; +use crate::context::{CheckLintNameResult, LintStore}; +use crate::late::unerased_lint_store; use rustc::hir::map::Map; -use rustc::lint::{LintLevelMap, LintLevelsBuilder, LintStore}; +use rustc::lint::struct_lint_level; +use rustc::lint::{LintLevelMap, LintLevelSets, LintSet, LintSource}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; +use rustc_data_structures::fx::FxHashMap; +use rustc_error_codes::*; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; +use rustc_session::lint::{builtin, Level, Lint}; +use rustc_session::Session; +use rustc_span::{sym, MultiSpan, Symbol}; use syntax::ast; +use syntax::attr; +use syntax::print::pprust; +use syntax::sess::feature_err; +use syntax::unwrap_or; -pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId}; +use std::cmp; fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); @@ -28,6 +41,378 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { tcx.arena.alloc(builder.levels.build_map()) } +pub struct LintLevelsBuilder<'a> { + sess: &'a Session, + sets: LintLevelSets, + id_to_set: FxHashMap, + cur: u32, + warn_about_weird_lints: bool, +} + +pub struct BuilderPush { + prev: u32, + pub changed: bool, +} + +impl<'a> LintLevelsBuilder<'a> { + pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { + let mut builder = LintLevelsBuilder { + sess, + sets: LintLevelSets::new(), + cur: 0, + id_to_set: Default::default(), + warn_about_weird_lints, + }; + builder.process_command_line(sess, store); + assert_eq!(builder.sets.list.len(), 1); + builder + } + + fn process_command_line(&mut self, sess: &Session, store: &LintStore) { + let mut specs = FxHashMap::default(); + self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); + + for &(ref lint_name, level) in &sess.opts.lint_opts { + store.check_lint_name_cmdline(sess, &lint_name, level); + + // If the cap is less than this specified level, e.g., if we've got + // `--cap-lints allow` but we've also got `-D foo` then we ignore + // this specification as the lint cap will set it to allow anyway. + let level = cmp::min(level, self.sets.lint_cap); + + let lint_flag_val = Symbol::intern(lint_name); + let ids = match store.find_lints(&lint_name) { + Ok(ids) => ids, + Err(_) => continue, // errors handled in check_lint_name_cmdline above + }; + for id in ids { + let src = LintSource::CommandLine(lint_flag_val); + specs.insert(id, (level, src)); + } + } + + self.sets.list.push(LintSet::CommandLine { specs }); + } + + /// Pushes a list of AST lint attributes onto this context. + /// + /// This function will return a `BuilderPush` object which should be passed + /// to `pop` when this scope for the attributes provided is exited. + /// + /// This function will perform a number of tasks: + /// + /// * It'll validate all lint-related attributes in `attrs` + /// * It'll mark all lint-related attributes as used + /// * Lint levels will be updated based on the attributes provided + /// * Lint attributes are validated, e.g., a #[forbid] can't be switched to + /// #[allow] + /// + /// Don't forget to call `pop`! + pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { + let mut specs = FxHashMap::default(); + let sess = self.sess; + let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); + for attr in attrs { + let level = match Level::from_symbol(attr.name_or_empty()) { + None => continue, + Some(lvl) => lvl, + }; + + let meta = unwrap_or!(attr.meta(), continue); + attr::mark_used(attr); + + let mut metas = unwrap_or!(meta.meta_item_list(), continue); + + if metas.is_empty() { + // FIXME (#55112): issue unused-attributes lint for `#[level()]` + continue; + } + + // Before processing the lint names, look for a reason (RFC 2383) + // at the end. + let mut reason = None; + let tail_li = &metas[metas.len() - 1]; + if let Some(item) = tail_li.meta_item() { + match item.kind { + ast::MetaItemKind::Word => {} // actual lint names handled later + ast::MetaItemKind::NameValue(ref name_value) => { + if item.path == sym::reason { + // found reason, reslice meta list to exclude it + metas = &metas[0..metas.len() - 1]; + // FIXME (#55112): issue unused-attributes lint if we thereby + // don't have any lint names (`#[level(reason = "foo")]`) + if let ast::LitKind::Str(rationale, _) = name_value.kind { + if !self.sess.features_untracked().lint_reasons { + feature_err( + &self.sess.parse_sess, + sym::lint_reasons, + item.span, + "lint reasons are experimental", + ) + .emit(); + } + reason = Some(rationale); + } else { + bad_attr(name_value.span) + .span_label(name_value.span, "reason must be a string literal") + .emit(); + } + } else { + bad_attr(item.span) + .span_label(item.span, "bad attribute argument") + .emit(); + } + } + ast::MetaItemKind::List(_) => { + bad_attr(item.span).span_label(item.span, "bad attribute argument").emit(); + } + } + } + + for li in metas { + let meta_item = match li.meta_item() { + Some(meta_item) if meta_item.is_word() => meta_item, + _ => { + let sp = li.span(); + let mut err = bad_attr(sp); + let mut add_label = true; + if let Some(item) = li.meta_item() { + if let ast::MetaItemKind::NameValue(_) = item.kind { + if item.path == sym::reason { + err.span_label(sp, "reason in lint attribute must come last"); + add_label = false; + } + } + } + if add_label { + err.span_label(sp, "bad attribute argument"); + } + err.emit(); + continue; + } + }; + let tool_name = if meta_item.path.segments.len() > 1 { + let tool_ident = meta_item.path.segments[0].ident; + if !attr::is_known_lint_tool(tool_ident) { + struct_span_err!( + sess, + tool_ident.span, + E0710, + "an unknown tool name found in scoped lint: `{}`", + pprust::path_to_string(&meta_item.path), + ) + .emit(); + continue; + } + + Some(tool_ident.name) + } else { + None + }; + let name = meta_item.path.segments.last().expect("empty lint name").ident.name; + match store.check_lint_name(&name.as_str(), tool_name) { + CheckLintNameResult::Ok(ids) => { + let src = LintSource::Node(name, li.span(), reason); + for id in ids { + specs.insert(*id, (level, src)); + } + } + + CheckLintNameResult::Tool(result) => { + match result { + Ok(ids) => { + let complete_name = &format!("{}::{}", tool_name.unwrap(), name); + let src = LintSource::Node( + Symbol::intern(complete_name), + li.span(), + reason, + ); + for id in ids { + specs.insert(*id, (level, src)); + } + } + Err((Some(ids), new_lint_name)) => { + let lint = builtin::RENAMED_AND_REMOVED_LINTS; + let (lvl, src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); + let msg = format!( + "lint name `{}` is deprecated \ + and may not have an effect in the future. \ + Also `cfg_attr(cargo-clippy)` won't be necessary anymore", + name + ); + struct_lint_level( + self.sess, + lint, + lvl, + src, + Some(li.span().into()), + &msg, + ) + .span_suggestion( + li.span(), + "change it to", + new_lint_name.to_string(), + Applicability::MachineApplicable, + ) + .emit(); + + let src = LintSource::Node( + Symbol::intern(&new_lint_name), + li.span(), + reason, + ); + for id in ids { + specs.insert(*id, (level, src)); + } + } + Err((None, _)) => { + // If Tool(Err(None, _)) is returned, then either the lint does not + // exist in the tool or the code was not compiled with the tool and + // therefore the lint was never added to the `LintStore`. To detect + // this is the responsibility of the lint tool. + } + } + } + + _ if !self.warn_about_weird_lints => {} + + CheckLintNameResult::Warning(msg, renamed) => { + let lint = builtin::RENAMED_AND_REMOVED_LINTS; + let (level, src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); + let mut err = struct_lint_level( + self.sess, + lint, + level, + src, + Some(li.span().into()), + &msg, + ); + if let Some(new_name) = renamed { + err.span_suggestion( + li.span(), + "use the new name", + new_name, + Applicability::MachineApplicable, + ); + } + err.emit(); + } + CheckLintNameResult::NoLint(suggestion) => { + let lint = builtin::UNKNOWN_LINTS; + let (level, src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); + let msg = format!("unknown lint: `{}`", name); + let mut db = struct_lint_level( + self.sess, + lint, + level, + src, + Some(li.span().into()), + &msg, + ); + + if let Some(suggestion) = suggestion { + db.span_suggestion( + li.span(), + "did you mean", + suggestion.to_string(), + Applicability::MachineApplicable, + ); + } + + db.emit(); + } + } + } + } + + for (id, &(level, ref src)) in specs.iter() { + if level == Level::Forbid { + continue; + } + let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) { + (Some(Level::Forbid), src) => src, + _ => continue, + }; + let forbidden_lint_name = match forbid_src { + LintSource::Default => id.to_string(), + LintSource::Node(name, _, _) => name.to_string(), + LintSource::CommandLine(name) => name.to_string(), + }; + let (lint_attr_name, lint_attr_span) = match *src { + LintSource::Node(name, span, _) => (name, span), + _ => continue, + }; + let mut diag_builder = struct_span_err!( + self.sess, + lint_attr_span, + E0453, + "{}({}) overruled by outer forbid({})", + level.as_str(), + lint_attr_name, + forbidden_lint_name + ); + diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); + match forbid_src { + LintSource::Default => {} + LintSource::Node(_, forbid_source_span, reason) => { + diag_builder.span_label(forbid_source_span, "`forbid` level set here"); + if let Some(rationale) = reason { + diag_builder.note(&rationale.as_str()); + } + } + LintSource::CommandLine(_) => { + diag_builder.note("`forbid` lint level was set on command line"); + } + } + diag_builder.emit(); + // don't set a separate error for every lint in the group + break; + } + + let prev = self.cur; + if specs.len() > 0 { + self.cur = self.sets.list.len() as u32; + self.sets.list.push(LintSet::Node { specs: specs, parent: prev }); + } + + BuilderPush { prev: prev, changed: prev != self.cur } + } + + /// Called after `push` when the scope of a set of attributes are exited. + pub fn pop(&mut self, push: BuilderPush) { + self.cur = push.prev; + } + + /// Used to emit a lint-related diagnostic based on the current state of + /// this lint context. + pub fn struct_lint( + &self, + lint: &'static Lint, + span: Option, + msg: &str, + ) -> DiagnosticBuilder<'a> { + let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess); + struct_lint_level(self.sess, lint, level, src, span, msg) + } + + /// Registers the ID provided with the current set of lints stored in + /// this context. + pub fn register_id(&mut self, id: HirId) { + self.id_to_set.insert(id, self.cur); + } + + pub fn build(self) -> LintLevelSets { + self.sets + } + + pub fn build_map(self) -> LintLevelMap { + LintLevelMap { sets: self.sets, id_to_set: self.id_to_set } + } +} + struct LintLevelMapBuilder<'a, 'tcx> { levels: LintLevelsBuilder<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e11472e1136f7..93eae1d6c1ae5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] +#![feature(never_type)] #![feature(nll)] #![recursion_limit = "256"] @@ -25,33 +26,29 @@ extern crate rustc_session; mod array_into_iter; pub mod builtin; +mod context; mod early; mod internal; mod late; mod levels; mod non_ascii_idents; mod nonstandard_style; +mod passes; mod redundant_semicolon; mod types; mod unused; -use rustc::lint; -use rustc::lint::builtin::{ - BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, - INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, -}; -use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_session::lint::{LintArray, LintPass}; - +use rustc_session::lint::builtin::{ + BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, + INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, +}; use rustc_span::Span; use syntax::ast; -use lint::LintId; - use array_into_iter::ArrayIntoIter; use builtin::*; use internal::*; @@ -61,10 +58,15 @@ use redundant_semicolon::*; use types::*; use unused::*; -/// Useful for other parts of the compiler. +/// Useful for other parts of the compiler / Clippy. pub use builtin::SoftLints; +pub use context::{EarlyContext, LateContext, LintContext, LintStore}; pub use early::check_ast_crate; pub use late::check_crate; +pub use passes::{EarlyLintPass, LateLintPass}; +pub use rustc_session::lint::Level::{self, *}; +pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; +pub use rustc_session::lint::{LintArray, LintPass}; pub fn provide(providers: &mut Providers<'_>) { levels::provide(providers); @@ -181,8 +183,8 @@ late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]) late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]); -pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore { - let mut lint_store = lint::LintStore::new(); +pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore { + let mut lint_store = LintStore::new(); register_builtins(&mut lint_store, no_interleave_lints); if internal_lints { @@ -195,7 +197,7 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint:: /// Tell the `LintStore` about all the built-in lints (the ones /// defined in this crate and the ones defined in /// `rustc::lint::builtin`). -fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) { +fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { macro_rules! add_lint_group { ($name:expr, $($lint:ident),*) => ( store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]); @@ -392,7 +394,7 @@ fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) { store.register_removed("plugin_as_library", "plugins have been deprecated and retired"); } -fn register_internals(store: &mut lint::LintStore) { +fn register_internals(store: &mut LintStore) { store.register_lints(&DefaultHashTypes::get_lints()); store.register_early_pass(|| box DefaultHashTypes::new()); store.register_lints(&LintPassImpl::get_lints()); diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index 522aeb6b14420..3c85a1b31b244 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -1,4 +1,4 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintContext}; +use crate::{EarlyContext, EarlyLintPass, LintContext}; use syntax::ast; declare_lint! { diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index f75bb9ba32c3d..a2b7884241ff7 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -1,4 +1,4 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/librustc/lint/passes.rs b/src/librustc_lint/passes.rs similarity index 96% rename from src/librustc/lint/passes.rs rename to src/librustc_lint/passes.rs index 41671ccc6c0fc..cb54105381fb2 100644 --- a/src/librustc/lint/passes.rs +++ b/src/librustc_lint/passes.rs @@ -18,23 +18,15 @@ //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. -pub use self::Level::*; -pub use crate::lint::LintSource::{self, *}; +use crate::context::{EarlyContext, LateContext}; use rustc_data_structures::sync; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; +use rustc_session::lint::LintPass; use rustc_span::Span; use syntax::ast; -pub use crate::lint::context::{ - add_elided_lifetime_in_path_suggestion, CheckLintNameResult, EarlyContext, LateContext, - LintContext, LintStore, -}; - -pub use rustc_session::lint::{builtin, LintArray, LintPass}; -pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId}; - #[macro_export] macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( @@ -169,6 +161,7 @@ macro_rules! declare_combined_late_lint_pass { expand_combined_late_lint_pass_methods!([$($passes),*], $methods); } + #[allow(rustc::lint_pass_impl_without_macro)] impl LintPass for $name { fn name(&self) -> &'static str { panic!() @@ -296,6 +289,7 @@ macro_rules! declare_combined_early_lint_pass { expand_combined_early_lint_pass_methods!([$($passes),*], $methods); } + #[allow(rustc::lint_pass_impl_without_macro)] impl LintPass for $name { fn name(&self) -> &'static str { panic!() diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs index dc18f15fe40cb..21b244ad75d4e 100644 --- a/src/librustc_lint/redundant_semicolon.rs +++ b/src/librustc_lint/redundant_semicolon.rs @@ -1,4 +1,4 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintContext}; +use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_errors::Applicability; use syntax::ast::{ExprKind, Stmt, StmtKind}; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index ab6841c0c09bc..674a82b61961c 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use rustc::lint::{LateContext, LateLintPass, LintContext}; +use crate::{LateContext, LateLintPass, LintContext}; use rustc::mir::interpret::{sign_extend, truncate}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx}; use rustc::ty::subst::SubstsRef; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index da8a23f041e58..26cbda3d97895 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -1,5 +1,4 @@ -use rustc::lint::builtin::UNUSED_ATTRIBUTES; -use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty::adjustment; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashMap; @@ -8,6 +7,7 @@ use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_session::lint::builtin::UNUSED_ATTRIBUTES; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; diff --git a/src/librustc_plugin_impl/Cargo.toml b/src/librustc_plugin_impl/Cargo.toml index d0b7accafd68b..41e6c699c340e 100644 --- a/src/librustc_plugin_impl/Cargo.toml +++ b/src/librustc_plugin_impl/Cargo.toml @@ -14,6 +14,7 @@ doctest = false rustc = { path = "../librustc" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } syntax = { path = "../libsyntax" } rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_plugin_impl/lib.rs b/src/librustc_plugin_impl/lib.rs index 682d223f565de..10712eb60b9e3 100644 --- a/src/librustc_plugin_impl/lib.rs +++ b/src/librustc_plugin_impl/lib.rs @@ -9,7 +9,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(nll)] -use rustc::lint::LintStore; +use rustc_lint::LintStore; pub mod build; pub mod load; From b59235975e43ef5f3ea9436a62f4f07ee5b9a63e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 07:58:48 +0100 Subject: [PATCH 12/14] lints: move a comment --- src/librustc_lint/lib.rs | 26 +++++++++++++++++++++----- src/librustc_lint/passes.rs | 20 -------------------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 93eae1d6c1ae5..6e3382dee9aae 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -1,9 +1,25 @@ -//! # Lints in the Rust compiler +//! Lints, aka compiler warnings. //! -//! This currently only contains the definitions and implementations -//! of most of the lints that `rustc` supports directly, it does not -//! contain the infrastructure for defining/registering lints. That is -//! available in `rustc::lint` and `rustc_driver::plugin` respectively. +//! A 'lint' check is a kind of miscellaneous constraint that a user _might_ +//! want to enforce, but might reasonably want to permit as well, on a +//! module-by-module basis. They contrast with static constraints enforced by +//! other phases of the compiler, which are generally required to hold in order +//! to compile the program at all. +//! +//! Most lints can be written as `LintPass` instances. These run after +//! all other analyses. The `LintPass`es built into rustc are defined +//! within `rustc_session::lint::builtin`, +//! which has further comments on how to add such a lint. +//! rustc can also load user-defined lint plugins via the plugin mechanism. +//! +//! Some of rustc's lints are defined elsewhere in the compiler and work by +//! calling `add_lint()` on the overall `Session` object. This works when +//! it happens before the main lint pass, which emits the lints stored by +//! `add_lint()`. To emit lints after the main lint pass (from codegen, for +//! example) requires more effort. See `emit_lint` and `GatherNodeLevels` +//! in `context.rs`. +//! +//! Some code also exists in `rustc_session::lint`, `rustc::lint`. //! //! ## Note //! diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs index cb54105381fb2..7e5d670767ad8 100644 --- a/src/librustc_lint/passes.rs +++ b/src/librustc_lint/passes.rs @@ -1,23 +1,3 @@ -//! Lints, aka compiler warnings. -//! -//! A 'lint' check is a kind of miscellaneous constraint that a user _might_ -//! want to enforce, but might reasonably want to permit as well, on a -//! module-by-module basis. They contrast with static constraints enforced by -//! other phases of the compiler, which are generally required to hold in order -//! to compile the program at all. -//! -//! Most lints can be written as `LintPass` instances. These run after -//! all other analyses. The `LintPass`es built into rustc are defined -//! within `builtin.rs`, which has further comments on how to add such a lint. -//! rustc can also load user-defined lint plugins via the plugin mechanism. -//! -//! Some of rustc's lints are defined elsewhere in the compiler and work by -//! calling `add_lint()` on the overall `Session` object. This works when -//! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from codegen, for -//! example) requires more effort. See `emit_lint` and `GatherNodeLevels` -//! in `context.rs`. - use crate::context::{EarlyContext, LateContext}; use rustc_data_structures::sync; From 8be2a04c7e6bf78a614840dc7152990a451ac4e0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 09:40:55 +0100 Subject: [PATCH 13/14] pacify the parallel compiler --- src/librustc/ty/context.rs | 5 +++-- src/librustc_lint/late.rs | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c28631b982577..99e6c62f61326 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -41,6 +41,7 @@ use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, Pr use crate::ty::{InferConst, ParamConst}; use crate::ty::{List, TyKind, TyS}; use crate::util::common::ErrorReported; +use rustc_data_structures::sync; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE}; @@ -951,7 +952,7 @@ pub struct GlobalCtxt<'tcx> { /// /// FIXME(Centril): consider `dyn LintStoreMarker` once /// we can upcast to `Any` for some additional type safety. - pub lint_store: Lrc, + pub lint_store: Lrc, pub dep_graph: DepGraph, @@ -1120,7 +1121,7 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc, + lint_store: Lrc, local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, diff --git a/src/librustc_lint/late.rs b/src/librustc_lint/late.rs index eb5f89c9507d3..30a3788377508 100644 --- a/src/librustc_lint/late.rs +++ b/src/librustc_lint/late.rs @@ -28,12 +28,14 @@ use syntax::ast; use syntax::walk_list; use log::debug; +use std::any::Any; use std::slice; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore { - tcx.lint_store.downcast_ref().unwrap() + let store: &dyn Any = &*tcx.lint_store; + store.downcast_ref().unwrap() } macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ From 51078ceb44e4482432a13171ddb9978df27dcfbf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 10 Jan 2020 06:53:07 +0100 Subject: [PATCH 14/14] fix ui-fulldeps & tests fallout --- src/librustc_interface/tests.rs | 42 +++++++++---------- .../auxiliary/issue-40001-plugin.rs | 6 +-- .../auxiliary/lint-for-crate-rpass.rs | 6 +-- .../ui-fulldeps/auxiliary/lint-for-crate.rs | 6 +-- .../auxiliary/lint-group-plugin-test.rs | 6 +-- .../ui-fulldeps/auxiliary/lint-plugin-test.rs | 6 +-- .../ui-fulldeps/auxiliary/lint-tool-test.rs | 6 +-- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index c2e9c35fcd4a7..ec75a1c6a3938 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -2,7 +2,7 @@ extern crate getopts; use crate::interface::parse_cfgspecs; -use rustc::lint; +use rustc::lint::Level; use rustc::middle::cstore; use rustc::session::config::{build_configuration, build_session_options, to_crate_config}; use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; @@ -186,24 +186,24 @@ fn test_lints_tracking_hash_different_values() { let mut v3 = Options::default(); v1.lint_opts = vec![ - (String::from("a"), lint::Allow), - (String::from("b"), lint::Warn), - (String::from("c"), lint::Deny), - (String::from("d"), lint::Forbid), + (String::from("a"), Level::Allow), + (String::from("b"), Level::Warn), + (String::from("c"), Level::Deny), + (String::from("d"), Level::Forbid), ]; v2.lint_opts = vec![ - (String::from("a"), lint::Allow), - (String::from("b"), lint::Warn), - (String::from("X"), lint::Deny), - (String::from("d"), lint::Forbid), + (String::from("a"), Level::Allow), + (String::from("b"), Level::Warn), + (String::from("X"), Level::Deny), + (String::from("d"), Level::Forbid), ]; v3.lint_opts = vec![ - (String::from("a"), lint::Allow), - (String::from("b"), lint::Warn), - (String::from("c"), lint::Forbid), - (String::from("d"), lint::Deny), + (String::from("a"), Level::Allow), + (String::from("b"), Level::Warn), + (String::from("c"), Level::Forbid), + (String::from("d"), Level::Deny), ]; assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); @@ -222,17 +222,17 @@ fn test_lints_tracking_hash_different_construction_order() { let mut v2 = Options::default(); v1.lint_opts = vec![ - (String::from("a"), lint::Allow), - (String::from("b"), lint::Warn), - (String::from("c"), lint::Deny), - (String::from("d"), lint::Forbid), + (String::from("a"), Level::Allow), + (String::from("b"), Level::Warn), + (String::from("c"), Level::Deny), + (String::from("d"), Level::Forbid), ]; v2.lint_opts = vec![ - (String::from("a"), lint::Allow), - (String::from("c"), lint::Deny), - (String::from("b"), lint::Warn), - (String::from("d"), lint::Forbid), + (String::from("a"), Level::Allow), + (String::from("c"), Level::Deny), + (String::from("b"), Level::Warn), + (String::from("d"), Level::Forbid), ]; assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash()); diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index abb2e93757ed3..725c350fe4e22 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -1,17 +1,17 @@ #![feature(box_syntax, plugin, plugin_registrar, rustc_private)] #![crate_type = "dylib"] -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; extern crate rustc_hir; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; extern crate rustc_span; extern crate syntax; use rustc_hir::intravisit; use rustc_hir as hir; use rustc_hir::Node; -use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext}; use rustc_driver::plugin::Registry; use rustc_span::source_map; use syntax::print::pprust; diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 4ccbe8a3c0eb0..98963a180c850 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -2,14 +2,14 @@ #![feature(plugin_registrar, rustc_private)] #![feature(box_syntax)] -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_span; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; extern crate syntax; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass}; +use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass}; use rustc_driver::plugin::Registry; use rustc_span::symbol::Symbol; use syntax::attr; diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 360bffaa46f2b..589477da62527 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -3,14 +3,14 @@ #![feature(plugin_registrar, rustc_private)] #![feature(box_syntax)] -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; extern crate rustc_hir; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; extern crate rustc_span; extern crate syntax; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray}; +use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray}; use rustc_driver::plugin::Registry; use rustc_span::symbol::Symbol; use syntax::attr; diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index 786c699947e47..2cc288c21e697 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -4,12 +4,12 @@ #![feature(box_syntax, rustc_private)] // Load rustc as a plugin to get macros. -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; extern crate rustc_hir; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId}; +use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId}; use rustc_driver::plugin::Registry; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index bb96dba21fc2e..c704701cc480b 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -6,11 +6,11 @@ extern crate syntax; // Load rustc as a plugin to get macros -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; -use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray}; +use rustc_lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray}; use rustc_driver::plugin::Registry; use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index 1704909813797..fa545ddc2bc6b 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -4,11 +4,11 @@ extern crate syntax; // Load rustc as a plugin to get macros -#[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_session; extern crate rustc_driver; +#[macro_use] extern crate rustc_lint; +#[macro_use] extern crate rustc_session; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId}; use rustc_driver::plugin::Registry; use syntax::ast; declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");