Skip to content

Commit 2437921

Browse files
committed
introduce duplicate attribute diagnostic logic
1 parent 8a407a8 commit 2437921

File tree

4 files changed

+112
-17
lines changed

4 files changed

+112
-17
lines changed

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

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

4-
use super::SingleAttributeParser;
54
use super::util::parse_version;
5+
use super::{AttributeDuplicates, SingleAttributeParser};
66
use crate::context::AcceptContext;
77
use crate::parser::ArgParser;
88
use crate::session_diagnostics;
@@ -43,12 +43,13 @@ fn get(
4343

4444
impl SingleAttributeParser for DeprecationParser {
4545
const PATH: &'static [Symbol] = &[sym::deprecated];
46+
const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing;
4647

47-
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
48+
fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) {
4849
// FIXME(jdonszelmann): merge with errors from check_attrs.rs
4950
cx.emit_err(session_diagnostics::UnusedMultiple {
50-
this: cx.attr_span,
51-
other: first_span,
51+
this: used,
52+
other: unused,
5253
name: sym::deprecated,
5354
});
5455
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use thin_vec::ThinVec;
2222

2323
use crate::context::{AcceptContext, FinalizeContext};
2424
use crate::parser::ArgParser;
25+
use crate::session_diagnostics::UnusedMultiple;
2526

2627
pub(crate) mod allow_unstable;
2728
pub(crate) mod cfg;
@@ -74,11 +75,28 @@ pub(crate) trait AttributeParser: Default + 'static {
7475
pub(crate) trait SingleAttributeParser: 'static {
7576
const PATH: &'static [Symbol];
7677

78+
<<<<<<< Conflict 1 of 1
79+
+++++++ Contents of side #1
7780
/// Called when a duplicate attribute is found.
81+
%%%%%%% Changes from base to side #2
82+
+ const ON_DUPLICATE_STRATEGY: AttributeDuplicates;
83+
+
84+
/// Caled when a duplicate attribute is found.
85+
>>>>>>> Conflict 1 of 1 ends
7886
///
79-
/// `first_span` is the span of the first occurrence of this attribute.
87+
/// - `unused` is the span of the attribute that was unused or bad because of some
88+
/// duplicate reason (see [`AttributeDuplicates`])
89+
/// - `used` is the span of the attribute that was used in favor of the unused attribute
8090
// FIXME(jdonszelmann): default error
81-
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
91+
fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) {
92+
cx.emit_err(UnusedMultiple {
93+
this: used,
94+
other: unused,
95+
name: Symbol::intern(
96+
&Self::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
97+
),
98+
});
99+
}
82100

83101
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
84102
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
@@ -94,12 +112,24 @@ impl<T: SingleAttributeParser> Default for Single<T> {
94112

95113
impl<T: SingleAttributeParser> AttributeParser for Single<T> {
96114
const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
97-
if let Some((_, s)) = group.1 {
98-
T::on_duplicate(cx, s);
99-
return;
100-
}
101-
102115
if let Some(pa) = T::convert(cx, args) {
116+
match T::ON_DUPLICATE_STRATEGY {
117+
// keep the first and error
118+
AttributeDuplicates::ErrorFollowing => {
119+
if let Some((_, unused)) = group.1 {
120+
T::on_duplicate(cx, cx.attr_span, unused);
121+
return;
122+
}
123+
}
124+
// keep the new one and warn about the previous,
125+
// then replace
126+
AttributeDuplicates::FutureWarnPreceding => {
127+
if let Some((_, used)) = group.1 {
128+
T::on_duplicate(cx, used, cx.attr_span);
129+
}
130+
}
131+
}
132+
103133
group.1 = Some((pa, cx.attr_span));
104134
}
105135
})];
@@ -109,6 +139,68 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
109139
}
110140
}
111141

142+
pub(crate) enum OnDuplicate {
143+
/// Give a default warning
144+
Warn,
145+
146+
/// Duplicates will be a warning, with a note that this will be an error in the future.
147+
WarnButFutureError,
148+
149+
/// Give a default error
150+
Error,
151+
152+
/// Ignore duplicates
153+
Ignore,
154+
155+
/// Custom function called when a duplicate attribute is found.
156+
///
157+
/// - `unused` is the span of the attribute that was unused or bad because of some
158+
/// duplicate reason (see [`AttributeDuplicates`])
159+
/// - `used` is the span of the attribute that was used in favor of the unused attribute
160+
Custom(fn(cx: &AcceptContext<'_>, used: Span, unused: Span)),
161+
}
162+
163+
impl OnDuplicate {
164+
fn exec<P: SingleAttributeParser>(&self, cx: &AcceptContext<'_>, used: Span, unused: Span) {
165+
match self {
166+
OnDuplicate::Warn => {
167+
todo!()
168+
}
169+
OnDuplicate::WarnButFutureError => {
170+
todo!()
171+
}
172+
OnDuplicate::Error => {
173+
cx.emit_err(UnusedMultiple {
174+
this: used,
175+
other: unused,
176+
name: Symbol::intern(
177+
&P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
178+
),
179+
});
180+
}
181+
OnDuplicate::Ignore => {}
182+
OnDuplicate::Custom(f) => f(cx, used, unused),
183+
}
184+
}
185+
}
186+
187+
pub(crate) enum AttributeDuplicates {
188+
/// Duplicates after the first attribute will be an error.
189+
///
190+
/// This should be used where duplicates would be ignored, but carry extra
191+
/// meaning that could cause confusion. For example, `#[stable(since="1.0")]
192+
/// #[stable(since="2.0")]`, which version should be used for `stable`?
193+
ErrorFollowing,
194+
195+
/// Duplicates preceding the last instance of the attribute will be a
196+
/// warning, with a note that this will be an error in the future.
197+
///
198+
/// This is the same as `FutureWarnFollowing`, except the last attribute is
199+
/// the one that is "used". Ideally these can eventually migrate to
200+
/// `ErrorPreceding`.
201+
FutureWarnPreceding,
202+
}
203+
112204
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
113205

114206
/// Alternative to [`AttributeParser`] that automatically handles state management.

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed;
88
use rustc_span::{Span, Symbol, sym};
99

1010
use super::util::parse_version;
11-
use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
11+
use super::{AcceptMapping, AttributeDuplicates, AttributeParser, SingleAttributeParser};
1212
use crate::context::{AcceptContext, FinalizeContext};
1313
use crate::parser::{ArgParser, MetaItemParser};
1414
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@@ -118,9 +118,10 @@ pub(crate) struct ConstStabilityIndirectParser;
118118
// FIXME(jdonszelmann): single word attribute group when we have these
119119
impl SingleAttributeParser for ConstStabilityIndirectParser {
120120
const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect];
121+
const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing;
121122

122123
// ignore
123-
fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
124+
fn on_duplicate(_cx: &AcceptContext<'_>, _used: Span, _unused: Span) {}
124125

125126
fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
126127
Some(AttributeKind::ConstStabilityIndirect)

compiler/rustc_attr_parsing/src/attributes/transparency.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_attr_data_structures::AttributeKind;
22
use rustc_span::hygiene::Transparency;
33
use rustc_span::{Span, Symbol, sym};
44

5-
use super::{AcceptContext, SingleAttributeParser};
5+
use super::{AcceptContext, AttributeDuplicates, SingleAttributeParser};
66
use crate::parser::ArgParser;
77

88
pub(crate) struct TransparencyParser;
@@ -11,10 +11,11 @@ pub(crate) struct TransparencyParser;
1111
#[allow(rustc::untranslatable_diagnostic)]
1212
#[allow(rustc::diagnostic_outside_of_impl)]
1313
impl SingleAttributeParser for TransparencyParser {
14-
const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency];
14+
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
15+
const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing;
1516

16-
fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) {
17-
cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
17+
fn on_duplicate(cx: &crate::context::AcceptContext<'_>, used: Span, unused: Span) {
18+
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
1819
}
1920

2021
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {

0 commit comments

Comments
 (0)