Make LintExpectationId
stable between compilation sessions (RFC-2383)
This commit is contained in:
parent
44cb8fa482
commit
33a5945069
10 changed files with 171 additions and 39 deletions
|
@ -3882,7 +3882,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_index",
|
"rustc_hir",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
|
@ -25,7 +25,7 @@ use Level::*;
|
||||||
|
|
||||||
use emitter::{is_case_difference, Emitter, EmitterWriter};
|
use emitter::{is_case_difference, Emitter, EmitterWriter};
|
||||||
use registry::Registry;
|
use registry::Registry;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_data_structures::stable_hasher::StableHasher;
|
use rustc_data_structures::stable_hasher::StableHasher;
|
||||||
use rustc_data_structures::sync::{self, Lock, Lrc};
|
use rustc_data_structures::sync::{self, Lock, Lrc};
|
||||||
use rustc_data_structures::AtomicRef;
|
use rustc_data_structures::AtomicRef;
|
||||||
|
@ -452,7 +452,14 @@ struct HandlerInner {
|
||||||
|
|
||||||
future_breakage_diagnostics: Vec<Diagnostic>,
|
future_breakage_diagnostics: Vec<Diagnostic>,
|
||||||
|
|
||||||
/// Lint [`Diagnostic`]s can be expected as described in [RFC-2383]. An
|
/// Expected [`Diagnostic`]s store a [`LintExpectationId`] as part of
|
||||||
|
/// the lint level. [`LintExpectationId`]s created early during the compilation
|
||||||
|
/// (before `HirId`s have been defined) are not stable and can therefore not be
|
||||||
|
/// stored on disk. This buffer stores these diagnostics until the ID has been
|
||||||
|
/// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`]s are the
|
||||||
|
/// submitted for storage and added to the list of fulfilled expectations.
|
||||||
|
unstable_expect_diagnostics: Vec<Diagnostic>,
|
||||||
|
|
||||||
/// expected diagnostic will have the level `Expect` which additionally
|
/// expected diagnostic will have the level `Expect` which additionally
|
||||||
/// carries the [`LintExpectationId`] of the expectation that can be
|
/// carries the [`LintExpectationId`] of the expectation that can be
|
||||||
/// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
|
/// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
|
||||||
|
@ -580,6 +587,7 @@ impl Handler {
|
||||||
emitted_diagnostics: Default::default(),
|
emitted_diagnostics: Default::default(),
|
||||||
stashed_diagnostics: Default::default(),
|
stashed_diagnostics: Default::default(),
|
||||||
future_breakage_diagnostics: Vec::new(),
|
future_breakage_diagnostics: Vec::new(),
|
||||||
|
unstable_expect_diagnostics: Vec::new(),
|
||||||
fulfilled_expectations: Default::default(),
|
fulfilled_expectations: Default::default(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -923,6 +931,28 @@ impl Handler {
|
||||||
self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
|
self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_unstable_expectation_id(
|
||||||
|
&self,
|
||||||
|
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
|
||||||
|
) {
|
||||||
|
let diags = std::mem::take(&mut self.inner.borrow_mut().unstable_expect_diagnostics);
|
||||||
|
if diags.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
for mut diag in diags.into_iter() {
|
||||||
|
if let Some(unstable_id) = diag.level.get_expectation_id() {
|
||||||
|
if let Some(stable_id) = unstable_to_stable.get(&unstable_id) {
|
||||||
|
diag.level = Level::Expect(*stable_id);
|
||||||
|
inner.fulfilled_expectations.insert(*stable_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*TRACK_DIAGNOSTICS)(&diag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This methods steals all [`LintExpectationId`]s that are stored inside
|
/// This methods steals all [`LintExpectationId`]s that are stored inside
|
||||||
/// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
|
/// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
|
||||||
pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
|
pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
|
||||||
|
@ -973,6 +1003,15 @@ impl HandlerInner {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The `LintExpectationId` can be stable or unstable depending on when it was created.
|
||||||
|
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
|
||||||
|
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||||
|
// a stable one by the `LintLevelsBuilder`.
|
||||||
|
if let Level::Expect(LintExpectationId::Unstable(_)) = diagnostic.level {
|
||||||
|
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(*TRACK_DIAGNOSTICS)(diagnostic);
|
(*TRACK_DIAGNOSTICS)(diagnostic);
|
||||||
|
|
||||||
if let Level::Expect(expectation_id) = diagnostic.level {
|
if let Level::Expect(expectation_id) = diagnostic.level {
|
||||||
|
@ -1322,6 +1361,13 @@ impl Level {
|
||||||
pub fn is_failure_note(&self) -> bool {
|
pub fn is_failure_note(&self) -> bool {
|
||||||
matches!(*self, FailureNote)
|
matches!(*self, FailureNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
||||||
|
match self {
|
||||||
|
Level::Expect(id) => Some(*id),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||||
|
|
|
@ -59,7 +59,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||||
F: FnOnce(&mut Self),
|
F: FnOnce(&mut Self),
|
||||||
{
|
{
|
||||||
let is_crate_node = id == ast::CRATE_NODE_ID;
|
let is_crate_node = id == ast::CRATE_NODE_ID;
|
||||||
let push = self.context.builder.push(attrs, is_crate_node);
|
let push = self.context.builder.push(attrs, is_crate_node, None);
|
||||||
|
|
||||||
self.check_id(id);
|
self.check_id(id);
|
||||||
self.enter_attrs(attrs);
|
self.enter_attrs(attrs);
|
||||||
f(self);
|
f(self);
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub fn check_expectations(tcx: TyCtxt<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_unfulfilled_expectation_lint(tcx: TyCtxt<'_>, expectation: &LintExpectation) {
|
fn emit_unfulfilled_expectation_lint(tcx: TyCtxt<'_>, expectation: &LintExpectation) {
|
||||||
// FIXME The current implementation doesn't cover cases where the
|
// FIXME: The current implementation doesn't cover cases where the
|
||||||
// `unfulfilled_lint_expectations` is actually expected by another lint
|
// `unfulfilled_lint_expectations` is actually expected by another lint
|
||||||
// expectation. This can be added here as we have the lint level of this
|
// expectation. This can be added here as we have the lint level of this
|
||||||
// expectation, and we can also mark the lint expectation it would fulfill
|
// expectation, and we can also mark the lint expectation it would fulfill
|
||||||
|
|
|
@ -32,17 +32,23 @@ fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
|
||||||
|
|
||||||
builder.levels.id_to_set.reserve(krate.owners.len() + 1);
|
builder.levels.id_to_set.reserve(krate.owners.len() + 1);
|
||||||
|
|
||||||
let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
|
let push =
|
||||||
|
builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID));
|
||||||
|
|
||||||
builder.levels.register_id(hir::CRATE_HIR_ID);
|
builder.levels.register_id(hir::CRATE_HIR_ID);
|
||||||
tcx.hir().walk_toplevel_module(&mut builder);
|
tcx.hir().walk_toplevel_module(&mut builder);
|
||||||
builder.levels.pop(push);
|
builder.levels.pop(push);
|
||||||
|
|
||||||
|
builder.levels.update_unstable_expectation_ids();
|
||||||
builder.levels.build_map()
|
builder.levels.build_map()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LintLevelsBuilder<'s> {
|
pub struct LintLevelsBuilder<'s> {
|
||||||
sess: &'s Session,
|
sess: &'s Session,
|
||||||
lint_expectations: FxHashMap<LintExpectationId, LintExpectation>,
|
lint_expectations: FxHashMap<LintExpectationId, LintExpectation>,
|
||||||
|
/// Each expectation has a stable and an unstable identifier. This map
|
||||||
|
/// is used to map from unstable to stable [`LintExpectationId`]s.
|
||||||
|
expectation_id_map: FxHashMap<LintExpectationId, LintExpectationId>,
|
||||||
sets: LintLevelSets,
|
sets: LintLevelSets,
|
||||||
id_to_set: FxHashMap<HirId, LintStackIndex>,
|
id_to_set: FxHashMap<HirId, LintStackIndex>,
|
||||||
cur: LintStackIndex,
|
cur: LintStackIndex,
|
||||||
|
@ -66,6 +72,7 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||||
let mut builder = LintLevelsBuilder {
|
let mut builder = LintLevelsBuilder {
|
||||||
sess,
|
sess,
|
||||||
lint_expectations: Default::default(),
|
lint_expectations: Default::default(),
|
||||||
|
expectation_id_map: Default::default(),
|
||||||
sets: LintLevelSets::new(),
|
sets: LintLevelSets::new(),
|
||||||
cur: COMMAND_LINE,
|
cur: COMMAND_LINE,
|
||||||
id_to_set: Default::default(),
|
id_to_set: Default::default(),
|
||||||
|
@ -226,13 +233,26 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||||
/// `#[allow]`
|
/// `#[allow]`
|
||||||
///
|
///
|
||||||
/// Don't forget to call `pop`!
|
/// 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,
|
||||||
|
source_hir_id: Option<HirId>,
|
||||||
|
) -> BuilderPush {
|
||||||
let mut specs = FxHashMap::default();
|
let mut specs = FxHashMap::default();
|
||||||
let sess = self.sess;
|
let sess = self.sess;
|
||||||
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
||||||
for attr in attrs {
|
for (attr_index, attr) in attrs.iter().enumerate() {
|
||||||
let Some(level) = Level::from_symbol(attr.name_or_empty(), attr.id.as_u32()) else {
|
let level = match Level::from_symbol(attr.name_or_empty(), || {
|
||||||
continue
|
LintExpectationId::Unstable(attr.id)
|
||||||
|
}) {
|
||||||
|
None => continue,
|
||||||
|
Some(Level::Expect(unstable_id)) if source_hir_id.is_some() => {
|
||||||
|
let stable_id =
|
||||||
|
self.create_stable_id(unstable_id, source_hir_id.unwrap(), attr_index);
|
||||||
|
Level::Expect(stable_id)
|
||||||
|
}
|
||||||
|
Some(lvl) => lvl,
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(mut metas) = attr.meta_item_list() else {
|
let Some(mut metas) = attr.meta_item_list() else {
|
||||||
|
@ -539,6 +559,19 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||||
BuilderPush { prev, changed: prev != self.cur }
|
BuilderPush { prev, changed: prev != self.cur }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_stable_id(
|
||||||
|
&mut self,
|
||||||
|
unstable_id: LintExpectationId,
|
||||||
|
hir_id: HirId,
|
||||||
|
attr_index: usize,
|
||||||
|
) -> LintExpectationId {
|
||||||
|
let stable_id = LintExpectationId::Stable { hir_id, attr_index };
|
||||||
|
|
||||||
|
self.expectation_id_map.insert(unstable_id, stable_id);
|
||||||
|
|
||||||
|
stable_id
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the lint is gated on a feature that is not enabled.
|
/// Checks if the lint is gated on a feature that is not enabled.
|
||||||
fn check_gated_lint(&self, lint_id: LintId, span: Span) {
|
fn check_gated_lint(&self, lint_id: LintId, span: Span) {
|
||||||
if let Some(feature) = lint_id.lint.feature_gate {
|
if let Some(feature) = lint_id.lint.feature_gate {
|
||||||
|
@ -582,6 +615,10 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||||
self.id_to_set.insert(id, self.cur);
|
self.id_to_set.insert(id, self.cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_unstable_expectation_ids(&self) {
|
||||||
|
self.sess.diagnostic().update_unstable_expectation_id(&self.expectation_id_map);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_map(self) -> LintLevelMap {
|
pub fn build_map(self) -> LintLevelMap {
|
||||||
LintLevelMap {
|
LintLevelMap {
|
||||||
sets: self.sets,
|
sets: self.sets,
|
||||||
|
@ -603,7 +640,8 @@ impl LintLevelMapBuilder<'_> {
|
||||||
{
|
{
|
||||||
let is_crate_hir = id == hir::CRATE_HIR_ID;
|
let is_crate_hir = id == hir::CRATE_HIR_ID;
|
||||||
let attrs = self.tcx.hir().attrs(id);
|
let attrs = self.tcx.hir().attrs(id);
|
||||||
let push = self.levels.push(attrs, is_crate_hir);
|
let push = self.levels.push(attrs, is_crate_hir, Some(id));
|
||||||
|
|
||||||
if push.changed {
|
if push.changed {
|
||||||
self.levels.register_id(id);
|
self.levels.register_id(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,8 @@ pub mod builtin;
|
||||||
mod context;
|
mod context;
|
||||||
mod early;
|
mod early;
|
||||||
mod enum_intrinsics_non_enums;
|
mod enum_intrinsics_non_enums;
|
||||||
pub mod hidden_unicode_codepoints;
|
|
||||||
mod expect;
|
mod expect;
|
||||||
|
pub mod hidden_unicode_codepoints;
|
||||||
mod internal;
|
mod internal;
|
||||||
mod late;
|
mod late;
|
||||||
mod levels;
|
mod levels;
|
||||||
|
|
|
@ -10,4 +10,4 @@ rustc_span = { path = "../rustc_span" }
|
||||||
rustc_serialize = { path = "../rustc_serialize" }
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
|
|
|
@ -5,7 +5,9 @@ extern crate rustc_macros;
|
||||||
|
|
||||||
pub use self::Level::*;
|
pub use self::Level::*;
|
||||||
use rustc_ast::node_id::{NodeId, NodeMap};
|
use rustc_ast::node_id::{NodeId, NodeMap};
|
||||||
|
use rustc_ast::AttrId;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||||
|
use rustc_hir::HirId;
|
||||||
use rustc_serialize::json::Json;
|
use rustc_serialize::json::Json;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
|
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
|
||||||
|
@ -48,29 +50,70 @@ pub enum Applicability {
|
||||||
Unspecified,
|
Unspecified,
|
||||||
}
|
}
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
/// Each lint expectation has a `LintExpectationId` assigned by the
|
||||||
/// FIXME: The lint expectation ID is currently a simple copy of the `AttrId`
|
/// [`LintLevelsBuilder`][`rustc_lint::levels::LintLevelsBuilder`]. Expected
|
||||||
/// that the expectation originated from. In the future it should be generated
|
/// [`Diagnostic`][`rustc_errors::Diagnostic`]s get the lint level `Expect` which
|
||||||
/// by other means. This is for one to keep the IDs independent of each other
|
/// stores the `LintExpectationId` to match it with the actual expectation later on.
|
||||||
/// and also to ensure that it is actually stable between compilation sessions.
|
///
|
||||||
/// (The `AttrId` for instance, is not stable).
|
/// The `LintExpectationId` has to be has stable between compilations, as diagnostic
|
||||||
///
|
/// instances might be loaded from cache. Lint messages can be emitted during an
|
||||||
/// Additionally, it would be nice if this generation could be moved into
|
/// `EarlyLintPass` operating on the AST and during a `LateLintPass` traversing the
|
||||||
/// [`Level::from_symbol`] to have it all contained in one module and to
|
/// HIR tree. The AST doesn't have enough information to create a stable id. The
|
||||||
/// make it simpler to use.
|
/// `LintExpectationId` will instead store the [`AttrId`] defining the expectation.
|
||||||
pub struct LintExpectationId {
|
/// These `LintExpectationId` will be updated to use the stable [`HirId`] once the
|
||||||
DEBUG_FORMAT = "LintExpectationId({})"
|
/// AST has been lowered. The transformation is done by the
|
||||||
|
/// [`LintLevelsBuilder`][`rustc_lint::levels::LintLevelsBuilder`]
|
||||||
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, Encodable, Decodable)]
|
||||||
|
pub enum LintExpectationId {
|
||||||
|
/// Used for lints emitted during the `EarlyLintPass`. This id is not
|
||||||
|
/// has stable and should not be cached.
|
||||||
|
Unstable(AttrId),
|
||||||
|
/// 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: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LintExpectationId {
|
||||||
|
pub fn is_stable(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
LintExpectationId::Unstable(_) => false,
|
||||||
|
LintExpectationId::Stable { .. } => true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rustc_data_structures::impl_stable_hash_via_hash!(LintExpectationId);
|
impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
|
||||||
|
#[inline]
|
||||||
|
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||||
|
match self {
|
||||||
|
LintExpectationId::Unstable(_) => {
|
||||||
|
unreachable!(
|
||||||
|
"HashStable should never be called for an unstable `LintExpectationId`"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LintExpectationId::Stable { hir_id, attr_index } => {
|
||||||
|
hir_id.hash_stable(hcx, hasher);
|
||||||
|
attr_index.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<HCX> ToStableHashKey<HCX> for LintExpectationId {
|
impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectationId {
|
||||||
type KeyType = u32;
|
type KeyType = (HirId, usize);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
||||||
self.as_u32()
|
match self {
|
||||||
|
LintExpectationId::Unstable(_) => {
|
||||||
|
unreachable!(
|
||||||
|
"HashStable should never be called for an unstable `LintExpectationId`"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LintExpectationId::Stable { hir_id, attr_index } => (*hir_id, *attr_index),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +176,13 @@ impl Level {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a symbol to a level.
|
/// Converts a symbol to a level.
|
||||||
pub fn from_symbol(x: Symbol, possible_lint_expect_id: u32) -> Option<Level> {
|
pub fn from_symbol<F>(x: Symbol, create_expectation_id: F) -> Option<Level>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> LintExpectationId,
|
||||||
|
{
|
||||||
match x {
|
match x {
|
||||||
sym::allow => Some(Level::Allow),
|
sym::allow => Some(Level::Allow),
|
||||||
sym::expect => Some(Level::Expect(LintExpectationId::from(possible_lint_expect_id))),
|
sym::expect => Some(Level::Expect(create_expectation_id())),
|
||||||
sym::warn => Some(Level::Warn),
|
sym::warn => Some(Level::Warn),
|
||||||
sym::deny => Some(Level::Deny),
|
sym::deny => Some(Level::Deny),
|
||||||
sym::forbid => Some(Level::Forbid),
|
sym::forbid => Some(Level::Forbid),
|
||||||
|
|
|
@ -6,10 +6,9 @@ use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId};
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_query_system::ich::StableHashingContext;
|
use rustc_query_system::ich::StableHashingContext;
|
||||||
use rustc_session::lint::LintExpectationId;
|
|
||||||
use rustc_session::lint::{
|
use rustc_session::lint::{
|
||||||
builtin::{self, FORBIDDEN_LINT_GROUPS},
|
builtin::{self, FORBIDDEN_LINT_GROUPS},
|
||||||
FutureIncompatibilityReason, Level, Lint, LintId,
|
FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId,
|
||||||
};
|
};
|
||||||
use rustc_session::{DiagnosticMessageId, Session};
|
use rustc_session::{DiagnosticMessageId, Session};
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
|
|
|
@ -49,7 +49,7 @@ use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
|
use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
|
||||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||||
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
|
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
|
||||||
use rustc_session::lint::{Level, Lint};
|
use rustc_session::lint::{Level, Lint, LintExpectationId};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
||||||
|
@ -2755,11 +2755,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
return bound;
|
return bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hir
|
if hir.attrs(id).iter().enumerate().any(|(attr_index, attr)| {
|
||||||
.attrs(id)
|
Level::from_symbol(attr.name_or_empty(), || LintExpectationId::Stable {
|
||||||
.iter()
|
hir_id: id,
|
||||||
.any(|attr| Level::from_symbol(attr.name_or_empty(), attr.id.as_u32()).is_some())
|
attr_index,
|
||||||
{
|
})
|
||||||
|
.is_some()
|
||||||
|
}) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
let next = hir.get_parent_node(id);
|
let next = hir.get_parent_node(id);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue