1717use std:: marker:: PhantomData ;
1818
1919use rustc_attr_data_structures:: AttributeKind ;
20- use rustc_span:: Span ;
20+ use rustc_span:: { Span , Symbol } ;
2121use thin_vec:: ThinVec ;
2222
2323use crate :: context:: { AcceptContext , FinalizeContext } ;
2424use crate :: parser:: ArgParser ;
25+ use crate :: session_diagnostics:: UnusedMultiple ;
2526
2627pub ( crate ) mod allow_unstable;
2728pub ( crate ) mod cfg;
@@ -74,11 +75,23 @@ pub(crate) trait AttributeParser: Default + 'static {
7475pub ( crate ) trait SingleAttributeParser : ' static {
7576 const PATH : & ' static [ rustc_span:: Symbol ] ;
7677
78+ const ON_DUPLICATE_STRATEGY : AttributeDuplicates ;
79+
7780 /// Caled when a duplicate attribute is found.
7881 ///
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
8085 // 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+ }
8295
8396 /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
8497 fn convert ( cx : & AcceptContext < ' _ > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > ;
@@ -94,12 +107,24 @@ impl<T: SingleAttributeParser> Default for Single<T> {
94107
95108impl < T : SingleAttributeParser > AttributeParser for Single < T > {
96109 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-
102110 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+
103128 group. 1 = Some ( ( pa, cx. attr_span ) ) ;
104129 }
105130 } ) ] ;
@@ -109,6 +134,68 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
109134 }
110135}
111136
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+
112199type ConvertFn < E > = fn ( ThinVec < E > ) -> AttributeKind ;
113200
114201/// Alternative to [`AttributeParser`] that automatically handles state management.
0 commit comments