mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
Split LintExpectationId
`LintExpectationId` has two variants, `Unstable` and `Stable`. There are some places where both variants are possible, but there are also places where only one of `Unstable` or `Stable` is possible. This commit encodes this into the type system by introducing new types `UnstableLintExpectationId` and `StableLintExpectationId`. The variants of `LintExpectationId` now enclose these. This makes it clearer what values are possible where. Other things of note: - `LintLevelsProvider` gets an associated type and some method changes. - `LintContext` gets an associated type. - `LevelSpec` is made generic. `UnstableLevelSpec` and `StableLevelSpec` typedefs are added. - The unstable types are now guaranteed by the type system to never be stably hashed. Previously this was a runtime check.
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::lint::LevelSpec;
|
||||
use rustc_middle::lint::StableLevelSpec;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
@@ -342,8 +342,8 @@ pub fn deserialize_rlink(
|
||||
/// Instead, encode exactly the information we need.
|
||||
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
|
||||
pub struct CodegenLintLevelSpecs {
|
||||
linker_messages: LevelSpec,
|
||||
linker_info: LevelSpec,
|
||||
linker_messages: StableLevelSpec,
|
||||
linker_info: StableLevelSpec,
|
||||
}
|
||||
|
||||
impl CodegenLintLevelSpecs {
|
||||
|
||||
@@ -20,14 +20,17 @@
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc_hir::{Pat, PatKind};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::LevelSpec;
|
||||
use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec};
|
||||
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
||||
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized,
|
||||
};
|
||||
use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
|
||||
use rustc_session::lint::{
|
||||
FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId,
|
||||
UnstableLintExpectationId,
|
||||
};
|
||||
use rustc_session::{DynLintStore, Session};
|
||||
use rustc_span::edit_distance::find_best_match_for_names;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
@@ -510,6 +513,8 @@ pub struct EarlyContext<'a> {
|
||||
}
|
||||
|
||||
pub trait LintContext {
|
||||
type LintExpectationId: Copy + Into<LintExpectationId>;
|
||||
|
||||
fn sess(&self) -> &Session;
|
||||
|
||||
// FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
|
||||
@@ -538,7 +543,7 @@ fn emit_span_lint<S: Into<MultiSpan>>(
|
||||
}
|
||||
|
||||
/// This returns the lint level spec for the given lint at the current location.
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec;
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
|
||||
|
||||
/// This function can be used to manually fulfill an expectation. This can
|
||||
/// be used for lints which contain several spans, and should be suppressed,
|
||||
@@ -547,7 +552,7 @@ fn emit_span_lint<S: Into<MultiSpan>>(
|
||||
/// Note that this function should only be called for [`LintExpectationId`]s
|
||||
/// retrieved from the current lint pass. Buffered or manually created ids can
|
||||
/// cause ICEs.
|
||||
fn fulfill_expectation(&self, expectation: LintExpectationId) {
|
||||
fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
|
||||
// We need to make sure that submitted expectation ids are correctly fulfilled suppressed
|
||||
// and stored between compilation sessions. To not manually do these steps, we simply create
|
||||
// a dummy diagnostic and emit it as usual, which will be suppressed and stored like a
|
||||
@@ -556,7 +561,7 @@ fn fulfill_expectation(&self, expectation: LintExpectationId) {
|
||||
.dcx()
|
||||
.struct_expect(
|
||||
"this is a dummy diagnostic, to submit and store an expectation",
|
||||
expectation,
|
||||
expectation.into(),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
@@ -585,6 +590,8 @@ pub(crate) fn new(
|
||||
}
|
||||
|
||||
impl<'tcx> LintContext for LateContext<'tcx> {
|
||||
type LintExpectationId = StableLintExpectationId;
|
||||
|
||||
/// Gets the overall compiler `Session` object.
|
||||
fn sess(&self) -> &Session {
|
||||
self.tcx.sess
|
||||
@@ -604,12 +611,14 @@ fn opt_span_lint<S: Into<MultiSpan>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec {
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
|
||||
self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl LintContext for EarlyContext<'_> {
|
||||
type LintExpectationId = UnstableLintExpectationId;
|
||||
|
||||
/// Gets the overall compiler `Session` object.
|
||||
fn sess(&self) -> &Session {
|
||||
self.builder.sess()
|
||||
@@ -624,7 +633,7 @@ fn opt_span_lint<S: Into<MultiSpan>>(
|
||||
self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
|
||||
}
|
||||
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec {
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
|
||||
self.builder.lint_level_spec(lint)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
use rustc_middle::lint::LintExpectation;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
|
||||
use rustc_session::lint::{LintExpectationId, StableLintExpectationId};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use crate::lints::{Expectation, ExpectationNote};
|
||||
@@ -12,7 +12,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { lint_expectations, check_expectations, ..*providers };
|
||||
}
|
||||
|
||||
fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> {
|
||||
fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(StableLintExpectationId, LintExpectation)> {
|
||||
let krate = tcx.hir_crate_items(());
|
||||
|
||||
let mut expectations = Vec::new();
|
||||
@@ -31,30 +31,22 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
|
||||
// Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair.
|
||||
let canonicalize_id = |expect_id: &LintExpectationId| {
|
||||
match *expect_id {
|
||||
LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => {
|
||||
(attr_id, lint_index)
|
||||
}
|
||||
LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
|
||||
let (attr_id, lint_index) = match *expect_id {
|
||||
LintExpectationId::Unstable(id) => (id.attr_id, id.lint_index),
|
||||
LintExpectationId::Stable(id) => {
|
||||
// We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
|
||||
let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id();
|
||||
|
||||
(attr_id, lint_index)
|
||||
(tcx.hir_attrs(id.hir_id)[id.attr_index as usize].id(), id.lint_index)
|
||||
}
|
||||
_ => panic!("fulfilled expectations must have a lint index"),
|
||||
}
|
||||
};
|
||||
(attr_id, lint_index.expect("fulfilled expectations must have a lint index"))
|
||||
};
|
||||
|
||||
let fulfilled_expectations: FxHashSet<_> =
|
||||
fulfilled_expectations.iter().map(canonicalize_id).collect();
|
||||
|
||||
for (expect_id, expectation) in lint_expectations {
|
||||
// This check will always be true, since `lint_expectations` only holds stable ids
|
||||
let LintExpectationId::Stable { hir_id, .. } = expect_id else {
|
||||
unreachable!("at this stage all `LintExpectationId`s are stable");
|
||||
};
|
||||
|
||||
let expect_id = canonicalize_id(expect_id);
|
||||
let hir_id = expect_id.hir_id;
|
||||
let expect_id = canonicalize_id(&LintExpectationId::Stable(*expect_id));
|
||||
|
||||
if !fulfilled_expectations.contains(&expect_id)
|
||||
&& tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter))
|
||||
@@ -63,7 +55,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
let note = expectation.is_unfulfilled_lint_expectations;
|
||||
tcx.emit_node_span_lint(
|
||||
UNFULFILLED_LINT_EXPECTATIONS,
|
||||
*hir_id,
|
||||
hir_id,
|
||||
expectation.emission_span,
|
||||
Expectation { rationale, note },
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_ast_pretty::pprust;
|
||||
@@ -11,8 +13,8 @@
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::lint::{
|
||||
LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, emit_lint_base,
|
||||
reveal_actual_level_spec,
|
||||
LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, StableLevelSpec,
|
||||
UnstableLevelSpec, emit_lint_base, reveal_actual_level_spec,
|
||||
};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
@@ -21,8 +23,10 @@
|
||||
self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
|
||||
UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
|
||||
};
|
||||
use rustc_session::lint::{Level, Lint, LintExpectationId, LintId};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_session::lint::{
|
||||
Level, Lint, LintExpectationId, LintId, StableLintExpectationId, UnstableLintExpectationId,
|
||||
};
|
||||
use rustc_span::{AttrId, DUMMY_SP, Span, Symbol, sym};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::builtin::MISSING_DOCS;
|
||||
@@ -64,9 +68,7 @@ struct LintStackIndex {
|
||||
/// to find the specifications for a given lint.
|
||||
#[derive(Debug)]
|
||||
struct LintSet {
|
||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `LevelSpec` for which
|
||||
// flag.
|
||||
specs: FxIndexMap<LintId, LevelSpec>,
|
||||
specs: FxIndexMap<LintId, UnstableLevelSpec>,
|
||||
parent: LintStackIndex,
|
||||
}
|
||||
|
||||
@@ -79,9 +81,9 @@ fn get_lint_level_spec(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
idx: LintStackIndex,
|
||||
aux: Option<&FxIndexMap<LintId, LevelSpec>>,
|
||||
aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
|
||||
sess: &Session,
|
||||
) -> LevelSpec {
|
||||
) -> UnstableLevelSpec {
|
||||
reveal_actual_level_spec(sess, LintId::of(lint), |id| {
|
||||
self.raw_lint_level_spec(id, idx, aux)
|
||||
})
|
||||
@@ -91,8 +93,8 @@ fn raw_lint_level_spec(
|
||||
&self,
|
||||
id: LintId,
|
||||
mut idx: LintStackIndex,
|
||||
aux: Option<&FxIndexMap<LintId, LevelSpec>>,
|
||||
) -> Option<LevelSpec> {
|
||||
aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
|
||||
) -> Option<UnstableLevelSpec> {
|
||||
if let Some(specs) = aux
|
||||
&& let Some(level_spec) = specs.get(&id)
|
||||
{
|
||||
@@ -213,26 +215,53 @@ pub struct TopDown {
|
||||
}
|
||||
|
||||
pub trait LintLevelsProvider {
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec>;
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec);
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> LevelSpec;
|
||||
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation);
|
||||
type LintExpectationId: Copy + Debug + Into<LintExpectationId>;
|
||||
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec<Self::LintExpectationId>>;
|
||||
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec<Self::LintExpectationId>);
|
||||
|
||||
fn get_lint_level_spec(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
sess: &Session,
|
||||
) -> LevelSpec<Self::LintExpectationId>;
|
||||
|
||||
fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation);
|
||||
|
||||
fn mk_lint_expectation_id(
|
||||
&self,
|
||||
attr_id: AttrId,
|
||||
attr_index: usize,
|
||||
lint_index: Option<u16>,
|
||||
) -> Self::LintExpectationId;
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for TopDown {
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec> {
|
||||
type LintExpectationId = UnstableLintExpectationId;
|
||||
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, UnstableLevelSpec> {
|
||||
&self.sets.list[self.cur].specs
|
||||
}
|
||||
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
fn insert(&mut self, id: LintId, level_spec: UnstableLevelSpec) {
|
||||
self.sets.list[self.cur].specs.insert(id, level_spec);
|
||||
}
|
||||
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> LevelSpec {
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> UnstableLevelSpec {
|
||||
self.sets.get_lint_level_spec(lint, self.cur, Some(self.current_specs()), sess)
|
||||
}
|
||||
|
||||
fn push_expectation(&mut self, _: LintExpectationId, _: LintExpectation) {}
|
||||
fn push_expectation(&mut self, _: Self::LintExpectationId, _: LintExpectation) {}
|
||||
|
||||
fn mk_lint_expectation_id(
|
||||
&self,
|
||||
attr_id: AttrId,
|
||||
_attr_index: usize,
|
||||
lint_index: Option<u16>,
|
||||
) -> Self::LintExpectationId {
|
||||
UnstableLintExpectationId { attr_id, lint_index }
|
||||
}
|
||||
}
|
||||
|
||||
struct LintLevelQueryMap<'tcx> {
|
||||
@@ -240,33 +269,44 @@ struct LintLevelQueryMap<'tcx> {
|
||||
cur: HirId,
|
||||
specs: ShallowLintLevelMap,
|
||||
/// Empty hash map to simplify code.
|
||||
empty: FxIndexMap<LintId, LevelSpec>,
|
||||
empty: FxIndexMap<LintId, StableLevelSpec>,
|
||||
attrs: &'tcx hir::AttributeMap<'tcx>,
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for LintLevelQueryMap<'_> {
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec> {
|
||||
type LintExpectationId = StableLintExpectationId;
|
||||
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, StableLevelSpec> {
|
||||
self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
|
||||
}
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
|
||||
fn insert(&mut self, id: LintId, level_spec: StableLevelSpec) {
|
||||
self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, level_spec);
|
||||
}
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> LevelSpec {
|
||||
|
||||
fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> StableLevelSpec {
|
||||
self.specs.lint_level_spec_at_node(self.tcx, LintId::of(lint), self.cur)
|
||||
}
|
||||
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
|
||||
|
||||
fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation) {
|
||||
self.specs.expectations.push((id, expectation))
|
||||
}
|
||||
|
||||
fn mk_lint_expectation_id(
|
||||
&self,
|
||||
_attr_id: AttrId,
|
||||
attr_index: usize,
|
||||
lint_index: Option<u16>,
|
||||
) -> Self::LintExpectationId {
|
||||
let attr_index = attr_index.try_into().unwrap();
|
||||
StableLintExpectationId { hir_id: self.cur, attr_index, lint_index }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
|
||||
fn add_id(&mut self, hir_id: HirId) {
|
||||
self.provider.cur = hir_id;
|
||||
self.add(
|
||||
self.provider.attrs.get(hir_id.local_id),
|
||||
hir_id == hir::CRATE_HIR_ID,
|
||||
Some(hir_id),
|
||||
);
|
||||
self.add(self.provider.attrs.get(hir_id.local_id), hir_id == hir::CRATE_HIR_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +426,7 @@ pub fn crate_root(
|
||||
crate_attrs: &[ast::Attribute],
|
||||
) -> Self {
|
||||
let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools);
|
||||
builder.add(crate_attrs, true, None);
|
||||
builder.add(crate_attrs, true);
|
||||
builder
|
||||
}
|
||||
|
||||
@@ -413,16 +453,12 @@ fn process_command_line(&mut self) {
|
||||
/// `#[allow]`
|
||||
///
|
||||
/// Don't forget to call `pop`!
|
||||
pub(crate) fn push(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
is_crate_node: bool,
|
||||
) -> BuilderPush {
|
||||
pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
|
||||
let prev = self.provider.cur;
|
||||
self.provider.cur =
|
||||
self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
|
||||
|
||||
self.add(attrs, is_crate_node, None);
|
||||
self.add(attrs, is_crate_node);
|
||||
|
||||
if self.provider.current_specs().is_empty() {
|
||||
self.provider.sets.list.pop();
|
||||
@@ -446,7 +482,10 @@ fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
||||
impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P>
|
||||
where
|
||||
LevelSpec<P::LintExpectationId>: Into<LevelSpec>,
|
||||
{
|
||||
pub(crate) fn sess(&self) -> &Session {
|
||||
self.sess
|
||||
}
|
||||
@@ -455,11 +494,11 @@ pub(crate) fn features(&self) -> &Features {
|
||||
self.features
|
||||
}
|
||||
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec> {
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec<P::LintExpectationId>> {
|
||||
self.provider.current_specs()
|
||||
}
|
||||
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
fn insert(&mut self, id: LintId, level_spec: LevelSpec<P::LintExpectationId>) {
|
||||
self.provider.insert(id, level_spec)
|
||||
}
|
||||
|
||||
@@ -536,7 +575,7 @@ fn add_command_line(&mut self) {
|
||||
/// Attempts to insert the `id` to `LevelSpec` map entry. If unsuccessful
|
||||
/// (e.g. if a forbid was already inserted on the same scope), then emits a
|
||||
/// diagnostic with no change to `specs`.
|
||||
fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec<P::LintExpectationId>) {
|
||||
let level = level_spec.level();
|
||||
let lint_id = level_spec.lint_id();
|
||||
let src = level_spec.src;
|
||||
@@ -561,7 +600,6 @@ fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
// as preventing `allow(lint)` for some lint `lint` in
|
||||
// `lint_group`. For now, issue a future-compatibility
|
||||
// warning for this case.
|
||||
let id_name = id.lint.name_lower();
|
||||
let fcw_warning = match old_src {
|
||||
LintLevelSource::Default => false,
|
||||
LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
|
||||
@@ -572,7 +610,7 @@ fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
fcw_warning,
|
||||
self.current_specs(),
|
||||
old_src,
|
||||
id_name
|
||||
id.lint.name_lower(),
|
||||
);
|
||||
let sub = match old_src {
|
||||
LintLevelSource::Default => {
|
||||
@@ -637,12 +675,7 @@ fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) {
|
||||
};
|
||||
}
|
||||
|
||||
fn add(
|
||||
&mut self,
|
||||
attrs: &[impl AttributeExt],
|
||||
is_crate_node: bool,
|
||||
source_hir_id: Option<HirId>,
|
||||
) {
|
||||
fn add(&mut self, attrs: &[impl AttributeExt], is_crate_node: bool) {
|
||||
let sess = self.sess;
|
||||
for (attr_index, attr) in attrs.iter().enumerate() {
|
||||
if attr.is_automatically_derived_attr() {
|
||||
@@ -662,23 +695,9 @@ fn add(
|
||||
continue;
|
||||
}
|
||||
|
||||
let (level, lint_id) = match Level::from_opt_symbol(attr.name()) {
|
||||
let level = match Level::from_opt_symbol(attr.name()) {
|
||||
None => continue,
|
||||
// `Expect` is the only lint level with a `LintExpectationId` that can be created
|
||||
// from an attribute.
|
||||
Some(Level::Expect) => {
|
||||
let id = if let Some(hir_id) = source_hir_id {
|
||||
LintExpectationId::Stable {
|
||||
hir_id,
|
||||
attr_index: attr_index.try_into().unwrap(),
|
||||
lint_index: None,
|
||||
}
|
||||
} else {
|
||||
LintExpectationId::Unstable { attr_id: attr.id(), lint_index: None }
|
||||
};
|
||||
(Level::Expect, Some(id))
|
||||
}
|
||||
Some(level) => (level, None),
|
||||
Some(level) => level,
|
||||
};
|
||||
|
||||
let Some(mut metas) = attr.meta_item_list() else { continue };
|
||||
@@ -726,10 +745,15 @@ fn add(
|
||||
}
|
||||
|
||||
for (lint_index, li) in metas.iter_mut().enumerate() {
|
||||
let mut lint_id = lint_id;
|
||||
if let Some(id) = &mut lint_id {
|
||||
id.set_lint_index(Some(lint_index as u16));
|
||||
}
|
||||
// `Expect` is the only lint level with a `LintExpectationId` that can be created
|
||||
// from an attribute.
|
||||
let lint_id = (level == Level::Expect).then(|| {
|
||||
self.provider.mk_lint_expectation_id(
|
||||
attr.id(),
|
||||
attr_index,
|
||||
Some(lint_index as u16),
|
||||
)
|
||||
});
|
||||
|
||||
let sp = li.span();
|
||||
let meta_item = match li {
|
||||
@@ -987,7 +1011,7 @@ fn into_diag(
|
||||
}
|
||||
|
||||
/// Find the lint level for a lint.
|
||||
pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec {
|
||||
pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<P::LintExpectationId> {
|
||||
self.provider.get_lint_level_spec(lint, self.sess)
|
||||
}
|
||||
|
||||
|
||||
@@ -100,47 +100,48 @@ pub enum Applicability {
|
||||
/// have that amount of lints listed. `u16` values should therefore suffice.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)]
|
||||
pub enum LintExpectationId {
|
||||
/// Used for lints emitted during the `EarlyLintPass`. This id is not
|
||||
/// hash stable and should not be cached.
|
||||
Unstable { attr_id: AttrId, lint_index: Option<u16> },
|
||||
/// The [`HirId`] that the lint expectation is attached to. This id is
|
||||
/// stable and can be cached. The additional index ensures that nodes with
|
||||
/// several expectations can correctly match diagnostics to the individual
|
||||
/// expectation.
|
||||
Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
|
||||
Unstable(UnstableLintExpectationId),
|
||||
Stable(StableLintExpectationId),
|
||||
}
|
||||
|
||||
impl LintExpectationId {
|
||||
pub fn is_stable(&self) -> bool {
|
||||
match self {
|
||||
LintExpectationId::Unstable { .. } => false,
|
||||
LintExpectationId::Stable { .. } => true,
|
||||
}
|
||||
}
|
||||
/// Used for lints emitted during the `EarlyLintPass`. This id is not hash
|
||||
/// stable and should not be cached.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)]
|
||||
pub struct UnstableLintExpectationId {
|
||||
pub attr_id: AttrId,
|
||||
pub lint_index: Option<u16>,
|
||||
}
|
||||
|
||||
pub fn set_lint_index(&mut self, new_lint_index: Option<u16>) {
|
||||
let (LintExpectationId::Unstable { lint_index, .. }
|
||||
| LintExpectationId::Stable { lint_index, .. }) = self;
|
||||
|
||||
*lint_index = new_lint_index
|
||||
impl From<UnstableLintExpectationId> for LintExpectationId {
|
||||
fn from(id: UnstableLintExpectationId) -> LintExpectationId {
|
||||
LintExpectationId::Unstable(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHash for LintExpectationId {
|
||||
/// The [`HirId`] that the lint expectation is attached to. This id is stable
|
||||
/// and can be cached. The additional index ensures that nodes with several
|
||||
/// expectations can correctly match diagnostics to the individual expectation.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)]
|
||||
pub struct StableLintExpectationId {
|
||||
pub hir_id: HirId,
|
||||
pub attr_index: u16,
|
||||
pub lint_index: Option<u16>,
|
||||
}
|
||||
|
||||
impl StableHash for StableLintExpectationId {
|
||||
#[inline]
|
||||
fn stable_hash<Hcx: StableHashCtxt>(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
|
||||
match self {
|
||||
LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
|
||||
hir_id.stable_hash(hcx, hasher);
|
||||
attr_index.stable_hash(hcx, hasher);
|
||||
lint_index.stable_hash(hcx, hasher);
|
||||
}
|
||||
_ => {
|
||||
unreachable!(
|
||||
"StableHash should only be called for filled and stable `LintExpectationId`"
|
||||
)
|
||||
}
|
||||
}
|
||||
let StableLintExpectationId { hir_id, attr_index, lint_index } = self;
|
||||
|
||||
hir_id.stable_hash(hcx, hasher);
|
||||
attr_index.stable_hash(hcx, hasher);
|
||||
lint_index.expect("must be filled to call `stable_hash`").stable_hash(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StableLintExpectationId> for LintExpectationId {
|
||||
fn from(id: StableLintExpectationId) -> LintExpectationId {
|
||||
LintExpectationId::Stable(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
use rustc_macros::{Decodable, Encodable, StableHash};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{
|
||||
FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, builtin,
|
||||
FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, StableLintExpectationId,
|
||||
UnstableLintExpectationId, builtin,
|
||||
};
|
||||
use rustc_span::{DUMMY_SP, ExpnKind, Span, Symbol, kw};
|
||||
use tracing::instrument;
|
||||
@@ -55,7 +56,7 @@ pub fn span(&self) -> Span {
|
||||
|
||||
/// Convenience helper for things that are frequently used together.
|
||||
#[derive(Copy, Clone, Debug, StableHash, Encodable, Decodable)]
|
||||
pub struct LevelSpec {
|
||||
pub struct LevelSpec<Id = LintExpectationId> {
|
||||
// This field *must* be private. It must be set in tandem with `lint_id`, only in
|
||||
// `LevelSpec::new`, because only certain `level`/`lint_id` combinations are valid. See
|
||||
// `LevelSpec::new` for those combinations.
|
||||
@@ -68,18 +69,17 @@ pub struct LevelSpec {
|
||||
level: Level,
|
||||
|
||||
// This field *must* be private. See the comment on `level`.
|
||||
lint_id: Option<LintExpectationId>,
|
||||
lint_id: Option<Id>,
|
||||
|
||||
pub src: LintLevelSource,
|
||||
}
|
||||
|
||||
impl LevelSpec {
|
||||
pub type UnstableLevelSpec = LevelSpec<UnstableLintExpectationId>;
|
||||
pub type StableLevelSpec = LevelSpec<StableLintExpectationId>;
|
||||
|
||||
impl<Id: Copy> LevelSpec<Id> {
|
||||
// Panics if an invalid `level`/`lint_id` combination is given.
|
||||
pub fn new(
|
||||
level: Level,
|
||||
lint_id: Option<LintExpectationId>,
|
||||
src: LintLevelSource,
|
||||
) -> LevelSpec {
|
||||
pub fn new(level: Level, lint_id: Option<Id>, src: LintLevelSource) -> LevelSpec<Id> {
|
||||
match (level, lint_id) {
|
||||
(Level::Allow | Level::Warn | Level::Deny | Level::Forbid, None) => {}
|
||||
(Level::Expect, Some(_)) => {}
|
||||
@@ -101,29 +101,45 @@ pub fn is_expect(self) -> bool {
|
||||
self.level == Level::Expect
|
||||
}
|
||||
|
||||
pub fn lint_id(self) -> Option<LintExpectationId> {
|
||||
pub fn lint_id(self) -> Option<Id> {
|
||||
self.lint_id
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnstableLevelSpec> for LevelSpec {
|
||||
fn from(level: UnstableLevelSpec) -> LevelSpec {
|
||||
let LevelSpec { level, lint_id, src } = level;
|
||||
let lint_id = lint_id.map(LintExpectationId::Unstable);
|
||||
LevelSpec { level, lint_id, src }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StableLevelSpec> for LevelSpec {
|
||||
fn from(level: StableLevelSpec) -> LevelSpec {
|
||||
let LevelSpec { level, lint_id, src } = level;
|
||||
let lint_id = lint_id.map(LintExpectationId::Stable);
|
||||
LevelSpec { level, lint_id, src }
|
||||
}
|
||||
}
|
||||
|
||||
/// Return type for the `shallow_lint_levels_on` query.
|
||||
///
|
||||
/// This map represents the set of allowed lints and allowance levels given
|
||||
/// by the attributes for *a single HirId*.
|
||||
#[derive(Default, Debug, StableHash)]
|
||||
pub struct ShallowLintLevelMap {
|
||||
pub expectations: Vec<(LintExpectationId, LintExpectation)>,
|
||||
pub specs: SortedMap<ItemLocalId, FxIndexMap<LintId, LevelSpec>>,
|
||||
pub expectations: Vec<(StableLintExpectationId, LintExpectation)>,
|
||||
pub specs: SortedMap<ItemLocalId, FxIndexMap<LintId, StableLevelSpec>>,
|
||||
}
|
||||
|
||||
/// Verify the effect of special annotations: `warnings` lint level and lint caps.
|
||||
///
|
||||
/// The return of this function is suitable for diagnostics.
|
||||
pub fn reveal_actual_level_spec(
|
||||
pub fn reveal_actual_level_spec<Id: Copy>(
|
||||
sess: &Session,
|
||||
lint: LintId,
|
||||
probe_for_lint_level_spec: impl Fn(LintId) -> Option<LevelSpec>,
|
||||
) -> LevelSpec {
|
||||
probe_for_lint_level_spec: impl Fn(LintId) -> Option<LevelSpec<Id>>,
|
||||
) -> LevelSpec<Id> {
|
||||
let level_spec = probe_for_lint_level_spec(lint);
|
||||
|
||||
// If `level` is none then we actually assume the default level for this lint.
|
||||
@@ -185,7 +201,7 @@ fn probe_for_lint_level_spec(
|
||||
tcx: TyCtxt<'_>,
|
||||
id: LintId,
|
||||
start: HirId,
|
||||
) -> Option<LevelSpec> {
|
||||
) -> Option<StableLevelSpec> {
|
||||
if let Some(map) = self.specs.get(&start.local_id)
|
||||
&& let Some(level_spec) = map.get(&id)
|
||||
{
|
||||
@@ -212,7 +228,12 @@ fn probe_for_lint_level_spec(
|
||||
|
||||
/// Fetch and return the user-visible lint level spec for the given lint at the given HirId.
|
||||
#[instrument(level = "trace", skip(self, tcx), ret)]
|
||||
pub fn lint_level_spec_at_node(&self, tcx: TyCtxt<'_>, lint: LintId, cur: HirId) -> LevelSpec {
|
||||
pub fn lint_level_spec_at_node(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
lint: LintId,
|
||||
cur: HirId,
|
||||
) -> StableLevelSpec {
|
||||
reveal_actual_level_spec(tcx.sess, lint, |lint| {
|
||||
self.probe_for_lint_level_spec(tcx, lint, cur)
|
||||
})
|
||||
@@ -221,7 +242,7 @@ pub fn lint_level_spec_at_node(&self, tcx: TyCtxt<'_>, lint: LintId, cur: HirId)
|
||||
|
||||
impl TyCtxt<'_> {
|
||||
/// Fetch and return the user-visible lint level spec for the given lint at the given HirId.
|
||||
pub fn lint_level_spec_at_node(self, lint: &'static Lint, id: HirId) -> LevelSpec {
|
||||
pub fn lint_level_spec_at_node(self, lint: &'static Lint, id: HirId) -> StableLevelSpec {
|
||||
self.shallow_lint_levels_on(id.owner).lint_level_spec_at_node(self, LintId::of(lint), id)
|
||||
}
|
||||
}
|
||||
@@ -362,7 +383,7 @@ fn explain_lint_level_source(
|
||||
pub fn emit_lint_base<'a, D: Diagnostic<'a, ()> + 'a>(
|
||||
sess: &'a Session,
|
||||
lint: &'static Lint,
|
||||
level_spec: LevelSpec,
|
||||
level_spec: impl Into<LevelSpec>,
|
||||
span: Option<MultiSpan>,
|
||||
decorate: D,
|
||||
) {
|
||||
@@ -556,7 +577,7 @@ fn emit_lint_base_impl<'a>(
|
||||
emit_lint_base_impl(
|
||||
sess,
|
||||
lint,
|
||||
level_spec,
|
||||
level_spec.into(),
|
||||
span,
|
||||
Box::new(move |dcx, level| decorate.into_diag(dcx, level)),
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
use rustc_session::cstore::{
|
||||
CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib,
|
||||
};
|
||||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_session::lint::StableLintExpectationId;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
@@ -558,7 +558,7 @@
|
||||
desc { "looking up lint levels for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
|
||||
query lint_expectations(_: ()) -> &'tcx Vec<(StableLintExpectationId, LintExpectation)> {
|
||||
arena_cache
|
||||
desc { "computing `#[expect]`ed lints in this crate" }
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::lint::builtin::{DEAD_CODE, DEAD_CODE_PUB_IN_BINARY};
|
||||
use rustc_session::lint::{self, Lint, LintExpectationId};
|
||||
use rustc_session::lint::{self, Lint, StableLintExpectationId};
|
||||
use rustc_span::{Symbol, kw};
|
||||
|
||||
use crate::errors::{
|
||||
@@ -1035,7 +1035,7 @@ fn mark_live_symbols_and_ignored_derived_traits(
|
||||
struct DeadItem {
|
||||
def_id: LocalDefId,
|
||||
name: Symbol,
|
||||
level_plus: (lint::Level, Option<LintExpectationId>),
|
||||
level_plus: (lint::Level, Option<StableLintExpectationId>),
|
||||
}
|
||||
|
||||
struct DeadVisitor<'tcx> {
|
||||
@@ -1082,7 +1082,10 @@ fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutFi
|
||||
ShouldWarnAboutField::Yes
|
||||
}
|
||||
|
||||
fn def_lint_level_plus(&self, id: LocalDefId) -> (lint::Level, Option<LintExpectationId>) {
|
||||
fn def_lint_level_plus(
|
||||
&self,
|
||||
id: LocalDefId,
|
||||
) -> (lint::Level, Option<StableLintExpectationId>) {
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(id);
|
||||
let level_spec = self.tcx.lint_level_spec_at_node(self.target_lint, hir_id);
|
||||
(level_spec.level(), level_spec.lint_id())
|
||||
@@ -1267,7 +1270,7 @@ fn warn_multiple(
|
||||
return;
|
||||
}
|
||||
// FIXME: `dead_codes` should probably be morally equivalent to
|
||||
// `IndexMap<(Level, LintExpectationId), (DefId, Symbol)>`
|
||||
// `IndexMap<(Level, StableLintExpectationId), (DefId, Symbol)>`
|
||||
dead_codes.sort_by_key(|v| v.level_plus.0);
|
||||
for group in dead_codes.chunk_by(|a, b| a.level_plus == b.level_plus) {
|
||||
self.lint_at_single_level(&group, participle, Some(def_id), report_on);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
|
||||
use rustc_middle::lint::LevelSpec;
|
||||
use rustc_middle::lint::UnstableLevelSpec;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{FileName, Span};
|
||||
use std::collections::BTreeMap;
|
||||
@@ -51,7 +51,7 @@
|
||||
struct Modules {
|
||||
local_path: PathBuf,
|
||||
spans: Vec<Span>,
|
||||
lint_level_specs: Vec<LevelSpec>,
|
||||
lint_level_specs: Vec<UnstableLevelSpec>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -96,7 +96,7 @@ fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
|
||||
.zip(lint_level_specs)
|
||||
.filter_map(|(span, level_spec)| {
|
||||
if let Some(id) = level_spec.lint_id() {
|
||||
cx.fulfill_expectation(id);
|
||||
cx.fulfill_expectation(id.into());
|
||||
}
|
||||
|
||||
(!matches!(level_spec.level(), Level::Allow | Level::Expect)).then_some(*span)
|
||||
|
||||
Reference in New Issue
Block a user