Skip to content

Commit 8b1a7f9

Browse files
committed
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 4f27f92 commit 8b1a7f9

File tree

20 files changed

+482
-217
lines changed

20 files changed

+482
-217
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,13 @@ 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 new_attrs = self.lower_attrs_vec(&e.attrs, e.span, ex.hir_id)
78+
.into_iter()
79+
.chain(old_attrs.iter().cloned());
7780
self.attrs.insert(
7881
ex.hir_id.local_id,
7982
&*self.arena.alloc_from_iter(
80-
self.lower_attrs_vec(&e.attrs, e.span)
81-
.into_iter()
82-
.chain(old_attrs.iter().cloned()),
83+
new_attrs,
8384
),
8485
);
8586
}
@@ -2025,7 +2026,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
20252026
let ret_expr = self.checked_return(Some(from_residual_expr));
20262027
self.arena.alloc(self.expr(try_span, ret_expr))
20272028
};
2028-
self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
2029+
self.lower_attrs(ret_expr.hir_id, &attrs, span);
20292030

20302031
let break_pat = self.pat_cf_break(try_span, residual_local);
20312032
self.arm(break_pat, ret_expr)

compiler/rustc_ast_lowering/src/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
5858
&mut self,
5959
owner: NodeId,
6060
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
61-
) {
61+
) {
6262
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
6363
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
6464

compiler/rustc_ast_lowering/src/lib.rs

+41-12
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5252
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};
55-
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
55+
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
5656
use rustc_hir::{
5757
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate,
5858
};
@@ -189,7 +189,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
189189
// interact with `gen`/`async gen` blocks
190190
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
191191

192-
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
192+
attribute_parser: AttributeParser::new(tcx, tcx.features(), registered_tools),
193193
}
194194
}
195195

@@ -198,6 +198,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
198198
}
199199
}
200200

201+
struct SpanLowerer {
202+
is_incremental: bool,
203+
defid: LocalDefId,
204+
}
205+
206+
impl SpanLowerer {
207+
fn lower(&self, span: Span) -> Span {
208+
if self.is_incremental {
209+
span.with_parent(Some(self.defid))
210+
} else {
211+
// Do not make spans relative when not using incremental compilation.
212+
span
213+
}
214+
}
215+
}
216+
201217
#[extension(trait ResolverAstLoweringExt)]
202218
impl ResolverAstLowering {
203219
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
@@ -741,15 +757,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
741757
})
742758
}
743759

760+
fn span_lowerer(&self) -> SpanLowerer {
761+
SpanLowerer {
762+
is_incremental: self.tcx.sess.opts.incremental.is_some(),
763+
defid: self.current_hir_id_owner.def_id,
764+
}
765+
}
766+
744767
/// Intercept all spans entering HIR.
745768
/// Mark a span as relative to the current owning item.
746769
fn lower_span(&self, span: Span) -> Span {
747-
if self.tcx.sess.opts.incremental.is_some() {
748-
span.with_parent(Some(self.current_hir_id_owner.def_id))
749-
} else {
750-
// Do not make spans relative when not using incremental compilation.
751-
span
752-
}
770+
self.span_lowerer().lower(span)
753771
}
754772

755773
fn lower_ident(&self, ident: Ident) -> Ident {
@@ -872,7 +890,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
872890
if attrs.is_empty() {
873891
&[]
874892
} else {
875-
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
893+
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
876894

877895
debug_assert_eq!(id.owner, self.current_hir_id_owner);
878896
let ret = self.arena.alloc_from_iter(lowered_attrs);
@@ -892,9 +910,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
892910
}
893911
}
894912

895-
fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
896-
self.attribute_parser
897-
.parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
913+
fn lower_attrs_vec(
914+
&mut self,
915+
attrs: &[Attribute],
916+
target_span: Span,
917+
target_hir_id: HirId,
918+
) -> Vec<hir::Attribute> {
919+
let l = self.span_lowerer();
920+
self.attribute_parser.parse_attribute_list(
921+
attrs,
922+
target_span,
923+
target_hir_id,
924+
OmitDoc::Lower,
925+
|s| l.lower(s),
926+
)
898927
}
899928

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

compiler/rustc_attr_parsing/messages.ftl

+10
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

+18-16
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 [rustc_span::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 [rustc_span::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

+4-4
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

+8-9
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
22
use rustc_span::symbol::Ident;
33
use rustc_span::{Span, Symbol, sym};
44

5-
use super::{AttributeDuplicates, OnDuplicate, SingleAttributeParser};
65
use super::util::parse_version;
7-
use super::{AttributeDuplicates, SingleAttributeParser};
8-
use crate::context::AcceptContext;
6+
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
7+
use crate::context::{AcceptContext, Stage};
98
use crate::parser::ArgParser;
109
use crate::session_diagnostics;
1110
use crate::session_diagnostics::UnsupportedLiteralReason;
1211

1312
pub(crate) struct DeprecationParser;
1413

15-
fn get(
16-
cx: &AcceptContext<'_>,
14+
fn get<S: Stage>(
15+
cx: &AcceptContext<'_, '_, S>,
1716
ident: Ident,
1817
param_span: Span,
1918
arg: &ArgParser<'_>,
@@ -46,12 +45,12 @@ fn get(
4645
}
4746
}
4847

49-
impl SingleAttributeParser for DeprecationParser {
48+
impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
5049
const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated];
51-
const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing;
52-
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
50+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
51+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
5352

54-
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
53+
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
5554
let features = cx.features();
5655

5756
let mut since = None;

0 commit comments

Comments
 (0)