Skip to content

Commit 60792be

Browse files
committed
introduce new lint infra
lint on duplicates during attribute parsing To do this we stuff them in the diagnostic context to be emitted after hir is constructed
1 parent 8e060c3 commit 60792be

File tree

32 files changed

+658
-231
lines changed

32 files changed

+658
-231
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,12 +3377,14 @@ dependencies = [
33773377
"rustc_ast",
33783378
"rustc_ast_pretty",
33793379
"rustc_attr_data_structures",
3380+
"rustc_data_structures",
33803381
"rustc_errors",
33813382
"rustc_feature",
33823383
"rustc_fluent_macro",
33833384
"rustc_hir",
33843385
"rustc_lexer",
33853386
"rustc_macros",
3387+
"rustc_middle",
33863388
"rustc_session",
33873389
"rustc_span",
33883390
"thin-vec",
@@ -3816,6 +3818,7 @@ dependencies = [
38163818
"rustc_arena",
38173819
"rustc_ast",
38183820
"rustc_attr_data_structures",
3821+
"rustc_attr_parsing",
38193822
"rustc_data_structures",
38203823
"rustc_errors",
38213824
"rustc_feature",

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
7474
// Merge attributes into the inner expression.
7575
if !e.attrs.is_empty() {
7676
let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
77-
let attrs = &*self.arena.alloc_from_iter(
78-
self.lower_attrs_vec(&e.attrs, e.span)
79-
.into_iter()
80-
.chain(old_attrs.iter().cloned()),
81-
);
82-
if attrs.is_empty() {
77+
let new_attrs = self
78+
.lower_attrs_vec(&e.attrs, e.span, ex.hir_id)
79+
.into_iter()
80+
.chain(old_attrs.iter().cloned());
81+
let new_attrs = &*self.arena.alloc_from_iter(new_attrs);
82+
if new_attrs.is_empty() {
8383
return ex;
8484
}
85-
86-
self.attrs.insert(ex.hir_id.local_id, attrs);
85+
self.attrs.insert(ex.hir_id.local_id, new_attrs);
8786
}
8887
return ex;
8988
}
@@ -2034,7 +2033,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
20342033
let ret_expr = self.checked_return(Some(from_residual_expr));
20352034
self.arena.alloc(self.expr(try_span, ret_expr))
20362035
};
2037-
self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
2036+
self.lower_attrs(ret_expr.hir_id, &attrs, span);
20382037

20392038
let break_pat = self.pat_cf_break(try_span, residual_local);
20402039
self.arm(break_pat, ret_expr)

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
5353
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
5454
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5555
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
56+
use rustc_hir::lints::DelayedLint;
5657
use rustc_hir::{
5758
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
5859
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
@@ -143,6 +144,8 @@ struct LoweringContext<'a, 'hir> {
143144
allow_for_await: Arc<[Symbol]>,
144145
allow_async_fn_traits: Arc<[Symbol]>,
145146

147+
delayed_lints: Vec<DelayedLint>,
148+
146149
attribute_parser: AttributeParser<'hir>,
147150
}
148151

@@ -191,7 +194,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
191194
// interact with `gen`/`async gen` blocks
192195
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
193196

194-
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
197+
attribute_parser: AttributeParser::new(tcx, tcx.features(), registered_tools),
198+
delayed_lints: Vec::new(),
195199
}
196200
}
197201

@@ -200,6 +204,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
200204
}
201205
}
202206

207+
struct SpanLowerer {
208+
is_incremental: bool,
209+
defid: LocalDefId,
210+
}
211+
212+
impl SpanLowerer {
213+
fn lower(&self, span: Span) -> Span {
214+
if self.is_incremental {
215+
span.with_parent(Some(self.defid))
216+
} else {
217+
// Do not make spans relative when not using incremental compilation.
218+
span
219+
}
220+
}
221+
}
222+
203223
#[extension(trait ResolverAstLoweringExt)]
204224
impl ResolverAstLowering {
205225
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
@@ -575,6 +595,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
575595
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
576596
let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
577597
let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
598+
let current_delayed_lints = std::mem::take(&mut self.delayed_lints);
578599

579600
// Do not reset `next_node_id` and `node_id_to_def_id`:
580601
// we want `f` to be able to refer to the `LocalDefId`s that the caller created.
@@ -608,6 +629,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
608629
self.item_local_id_counter = current_local_counter;
609630
self.impl_trait_defs = current_impl_trait_defs;
610631
self.impl_trait_bounds = current_impl_trait_bounds;
632+
self.delayed_lints = current_delayed_lints;
611633

612634
debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id));
613635
self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info)));
@@ -618,6 +640,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
618640
let mut bodies = std::mem::take(&mut self.bodies);
619641
let define_opaque = std::mem::take(&mut self.define_opaque);
620642
let trait_map = std::mem::take(&mut self.trait_map);
643+
let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
621644

622645
#[cfg(debug_assertions)]
623646
for (id, attrs) in attrs.iter() {
@@ -631,14 +654,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
631654
let bodies = SortedMap::from_presorted_elements(bodies);
632655

633656
// Don't hash unless necessary, because it's expensive.
634-
let (opt_hash_including_bodies, attrs_hash) =
635-
self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
657+
let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
658+
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
636659
let num_nodes = self.item_local_id_counter.as_usize();
637660
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
638661
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
639662
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
663+
let delayed_lints =
664+
hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
640665

641-
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
666+
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
642667
}
643668

644669
/// This method allocates a new `HirId` for the given `NodeId`.
@@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
759784
})
760785
}
761786

787+
fn span_lowerer(&self) -> SpanLowerer {
788+
SpanLowerer {
789+
is_incremental: self.tcx.sess.opts.incremental.is_some(),
790+
defid: self.current_hir_id_owner.def_id,
791+
}
792+
}
793+
762794
/// Intercept all spans entering HIR.
763795
/// Mark a span as relative to the current owning item.
764796
fn lower_span(&self, span: Span) -> Span {
765-
if self.tcx.sess.opts.incremental.is_some() {
766-
span.with_parent(Some(self.current_hir_id_owner.def_id))
767-
} else {
768-
// Do not make spans relative when not using incremental compilation.
769-
span
770-
}
797+
self.span_lowerer().lower(span)
771798
}
772799

773800
fn lower_ident(&self, ident: Ident) -> Ident {
@@ -889,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
889916
if attrs.is_empty() {
890917
&[]
891918
} else {
892-
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
919+
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
893920

894921
debug_assert_eq!(id.owner, self.current_hir_id_owner);
895922
let ret = self.arena.alloc_from_iter(lowered_attrs);
@@ -909,9 +936,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
909936
}
910937
}
911938

912-
fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
913-
self.attribute_parser
914-
.parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
939+
fn lower_attrs_vec(
940+
&mut self,
941+
attrs: &[Attribute],
942+
target_span: Span,
943+
target_hir_id: HirId,
944+
) -> Vec<hir::Attribute> {
945+
let l = self.span_lowerer();
946+
self.attribute_parser.parse_attribute_list(
947+
attrs,
948+
target_span,
949+
target_hir_id,
950+
OmitDoc::Lower,
951+
|s| l.lower(s),
952+
|l| {
953+
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
954+
},
955+
)
915956
}
916957

917958
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {

compiler/rustc_attr_data_structures/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mod attributes;
88
mod stability;
99
mod version;
1010

11+
pub mod lints;
12+
1113
use std::num::NonZero;
1214

1315
pub use attributes::*;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use rustc_macros::HashStable_Generic;
2+
use rustc_span::Span;
3+
4+
#[derive(Clone, Debug, HashStable_Generic)]
5+
pub struct AttributeLint<Id> {
6+
pub id: Id,
7+
pub span: Span,
8+
pub kind: AttributeLintKind,
9+
}
10+
11+
#[derive(Clone, Debug, HashStable_Generic)]
12+
pub enum AttributeLintKind {
13+
UnusedDuplicate { this: Span, other: Span, warning: bool },
14+
}

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ rustc_abi = { path = "../rustc_abi" }
99
rustc_ast = { path = "../rustc_ast" }
1010
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
1111
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
12+
rustc_data_structures = { path = "../rustc_data_structures" }
1213
rustc_errors = { path = "../rustc_errors" }
1314
rustc_feature = { path = "../rustc_feature" }
1415
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1516
rustc_hir = { path = "../rustc_hir" }
1617
rustc_lexer = { path = "../rustc_lexer" }
1718
rustc_macros = { path = "../rustc_macros" }
19+
rustc_middle = { path = "../rustc_middle" }
1820
rustc_session = { path = "../rustc_session" }
1921
rustc_span = { path = "../rustc_span" }
2022
thin-vec = "0.2.12"

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,17 @@ attr_parsing_unsupported_literal_generic =
131131
attr_parsing_unsupported_literal_suggestion =
132132
consider removing the prefix
133133
134+
attr_parsing_unused_duplicate =
135+
unused attribute
136+
.suggestion = remove this attribute
137+
.note = attribute also specified here
138+
.warn = {-attr_parsing_previously_accepted}
139+
140+
134141
attr_parsing_unused_multiple =
135142
multiple `{$name}` attributes
136143
.suggestion = remove this attribute
137144
.note = attribute also specified here
145+
146+
-attr_parsing_perviously_accepted =
147+
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind;
44
use rustc_span::{Span, Symbol, sym};
55

66
use super::{CombineAttributeParser, ConvertFn};
7-
use crate::context::AcceptContext;
7+
use crate::context::{AcceptContext, Stage};
88
use crate::parser::ArgParser;
99
use crate::session_diagnostics;
1010

1111
pub(crate) struct AllowInternalUnstableParser;
12-
impl CombineAttributeParser for AllowInternalUnstableParser {
12+
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
1313
const PATH: &'static [Symbol] = &[sym::allow_internal_unstable];
1414
type Item = (Symbol, Span);
1515
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
1616

17-
fn extend<'a>(
18-
cx: &'a AcceptContext<'a>,
19-
args: &'a ArgParser<'a>,
20-
) -> impl IntoIterator<Item = Self::Item> + 'a {
21-
parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
17+
fn extend<'c>(
18+
cx: &'c mut AcceptContext<'_, '_, S>,
19+
args: &'c ArgParser<'_>,
20+
) -> impl IntoIterator<Item = Self::Item> {
21+
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
22+
.into_iter()
23+
.zip(iter::repeat(cx.attr_span))
2224
}
2325
}
2426

2527
pub(crate) struct AllowConstFnUnstableParser;
26-
impl CombineAttributeParser for AllowConstFnUnstableParser {
28+
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
2729
const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
2830
type Item = Symbol;
2931
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
3032

31-
fn extend<'a>(
32-
cx: &'a AcceptContext<'a>,
33-
args: &'a ArgParser<'a>,
34-
) -> impl IntoIterator<Item = Self::Item> + 'a {
35-
parse_unstable(cx, args, Self::PATH[0])
33+
fn extend<'c>(
34+
cx: &'c mut AcceptContext<'_, '_, S>,
35+
args: &'c ArgParser<'_>,
36+
) -> impl IntoIterator<Item = Self::Item> + 'c {
37+
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
3638
}
3739
}
3840

39-
fn parse_unstable<'a>(
40-
cx: &AcceptContext<'_>,
41-
args: &'a ArgParser<'a>,
41+
fn parse_unstable<S: Stage>(
42+
cx: &AcceptContext<'_, '_, S>,
43+
args: &ArgParser<'_>,
4244
symbol: Symbol,
4345
) -> impl IntoIterator<Item = Symbol> {
4446
let mut res = Vec::new();

compiler/rustc_attr_parsing/src/attributes/confusables.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym};
33
use thin_vec::ThinVec;
44

55
use super::{AcceptMapping, AttributeParser};
6-
use crate::context::FinalizeContext;
6+
use crate::context::{FinalizeContext, Stage};
77
use crate::session_diagnostics;
88

99
#[derive(Default)]
@@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser {
1212
first_span: Option<Span>,
1313
}
1414

15-
impl AttributeParser for ConfusablesParser {
16-
const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
15+
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
16+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
1717
let Some(list) = args.list() else {
1818
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
1919
// NOTE: currently subsequent attributes are silently ignored using
@@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser {
4545
this.first_span.get_or_insert(cx.attr_span);
4646
})];
4747

48-
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
48+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
4949
if self.confusables.is_empty() {
5050
return None;
5151
}

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
22
use rustc_span::{Span, Symbol, sym};
33

44
use super::util::parse_version;
5-
use super::{AttributeDuplicates, OnDuplicate, SingleAttributeParser};
6-
use crate::context::AcceptContext;
5+
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
6+
use crate::context::{AcceptContext, Stage};
77
use crate::parser::ArgParser;
88
use crate::session_diagnostics;
99
use crate::session_diagnostics::UnsupportedLiteralReason;
1010

1111
pub(crate) struct DeprecationParser;
1212

13-
fn get(
14-
cx: &AcceptContext<'_>,
13+
fn get<S: Stage>(
14+
cx: &AcceptContext<'_, '_, S>,
1515
name: Symbol,
1616
param_span: Span,
1717
arg: &ArgParser<'_>,
@@ -41,12 +41,12 @@ fn get(
4141
}
4242
}
4343

44-
impl SingleAttributeParser for DeprecationParser {
44+
impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
4545
const PATH: &'static [Symbol] = &[sym::deprecated];
46-
const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing;
47-
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
46+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
47+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
4848

49-
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
49+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
5050
let features = cx.features();
5151

5252
let mut since = None;

0 commit comments

Comments
 (0)