17
17
use std:: marker:: PhantomData ;
18
18
19
19
use rustc_attr_data_structures:: AttributeKind ;
20
- use rustc_span:: Span ;
20
+ use rustc_span:: { Span , Symbol } ;
21
21
use thin_vec:: ThinVec ;
22
22
23
23
use crate :: context:: { AcceptContext , FinalizeContext } ;
24
24
use crate :: parser:: ArgParser ;
25
+ use crate :: session_diagnostics:: UnusedMultiple ;
25
26
26
27
pub ( crate ) mod allow_unstable;
27
28
pub ( crate ) mod cfg;
@@ -74,11 +75,23 @@ pub(crate) trait AttributeParser: Default + 'static {
74
75
pub ( crate ) trait SingleAttributeParser : ' static {
75
76
const PATH : & ' static [ rustc_span:: Symbol ] ;
76
77
78
+ const ON_DUPLICATE_STRATEGY : AttributeDuplicates ;
79
+
77
80
/// Caled when a duplicate attribute is found.
78
81
///
79
- /// `first_span` is the span of the first occurrence of this attribute.
82
+ /// - `unused` is the span of the attribute that was unused or bad because of some
83
+ /// duplicate reason (see [`AttributeDuplicates`])
84
+ /// - `used` is the span of the attribute that was used in favor of the unused attribute
80
85
// FIXME(jdonszelmann): default error
81
- fn on_duplicate ( cx : & AcceptContext < ' _ > , first_span : Span ) ;
86
+ fn on_duplicate ( cx : & AcceptContext < ' _ > , used : Span , unused : Span ) {
87
+ cx. emit_err ( UnusedMultiple {
88
+ this : used,
89
+ other : unused,
90
+ name : Symbol :: intern (
91
+ & Self :: PATH . into_iter ( ) . map ( |i| i. to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( ".." ) ,
92
+ ) ,
93
+ } ) ;
94
+ }
82
95
83
96
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
84
97
fn convert ( cx : & AcceptContext < ' _ > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > ;
@@ -94,12 +107,24 @@ impl<T: SingleAttributeParser> Default for Single<T> {
94
107
95
108
impl < T : SingleAttributeParser > AttributeParser for Single < T > {
96
109
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
-
102
110
if let Some ( pa) = T :: convert ( cx, args) {
111
+ match T :: ON_DUPLICATE_STRATEGY {
112
+ // keep the first and error
113
+ AttributeDuplicates :: ErrorFollowing => {
114
+ if let Some ( ( _, unused) ) = group. 1 {
115
+ T :: on_duplicate ( cx, cx. attr_span , unused) ;
116
+ return ;
117
+ }
118
+ }
119
+ // keep the new one and warn about the previous,
120
+ // then replace
121
+ AttributeDuplicates :: FutureWarnPreceding => {
122
+ if let Some ( ( _, used) ) = group. 1 {
123
+ T :: on_duplicate ( cx, used, cx. attr_span ) ;
124
+ }
125
+ }
126
+ }
127
+
103
128
group. 1 = Some ( ( pa, cx. attr_span ) ) ;
104
129
}
105
130
} ) ] ;
@@ -109,6 +134,68 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
109
134
}
110
135
}
111
136
137
+ pub ( crate ) enum OnDuplicate {
138
+ /// Give a default warning
139
+ Warn ,
140
+
141
+ /// Duplicates will be a warning, with a note that this will be an error in the future.
142
+ WarnButFutureError ,
143
+
144
+ /// Give a default error
145
+ Error ,
146
+
147
+ /// Ignore duplicates
148
+ Ignore ,
149
+
150
+ /// Custom function called when a duplicate attribute is found.
151
+ ///
152
+ /// - `unused` is the span of the attribute that was unused or bad because of some
153
+ /// duplicate reason (see [`AttributeDuplicates`])
154
+ /// - `used` is the span of the attribute that was used in favor of the unused attribute
155
+ Custom ( fn ( cx : & AcceptContext < ' _ > , used : Span , unused : Span ) ) ,
156
+ }
157
+
158
+ impl OnDuplicate {
159
+ fn exec < P : SingleAttributeParser > ( & self , cx : & AcceptContext < ' _ > , used : Span , unused : Span ) {
160
+ match self {
161
+ OnDuplicate :: Warn => {
162
+ todo ! ( )
163
+ }
164
+ OnDuplicate :: WarnButFutureError => {
165
+ todo ! ( )
166
+ }
167
+ OnDuplicate :: Error => {
168
+ cx. emit_err ( UnusedMultiple {
169
+ this : used,
170
+ other : unused,
171
+ name : Symbol :: intern (
172
+ & P :: PATH . into_iter ( ) . map ( |i| i. to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( ".." ) ,
173
+ ) ,
174
+ } ) ;
175
+ }
176
+ OnDuplicate :: Ignore => { }
177
+ OnDuplicate :: Custom ( f) => f ( cx, used, unused) ,
178
+ }
179
+ }
180
+ }
181
+
182
+ pub ( crate ) enum AttributeDuplicates {
183
+ /// Duplicates after the first attribute will be an error.
184
+ ///
185
+ /// This should be used where duplicates would be ignored, but carry extra
186
+ /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
187
+ /// #[stable(since="2.0")]`, which version should be used for `stable`?
188
+ ErrorFollowing ,
189
+
190
+ /// Duplicates preceding the last instance of the attribute will be a
191
+ /// warning, with a note that this will be an error in the future.
192
+ ///
193
+ /// This is the same as `FutureWarnFollowing`, except the last attribute is
194
+ /// the one that is "used". Ideally these can eventually migrate to
195
+ /// `ErrorPreceding`.
196
+ FutureWarnPreceding ,
197
+ }
198
+
112
199
type ConvertFn < E > = fn ( ThinVec < E > ) -> AttributeKind ;
113
200
114
201
/// Alternative to [`AttributeParser`] that automatically handles state management.
0 commit comments