@@ -94,39 +94,66 @@ pub enum OptimizeAttr {
94
94
///
95
95
/// - `#[stable]`
96
96
/// - `#[unstable]`
97
- #[ derive( Encodable , Decodable , Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
97
+ #[ derive( Encodable , Decodable , Clone , Debug , PartialEq , Eq , Hash ) ]
98
98
#[ derive( HashStable_Generic ) ]
99
99
pub struct Stability {
100
100
pub level : StabilityLevel ,
101
- pub feature : Symbol ,
102
101
}
103
102
104
103
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
105
- #[ derive( Encodable , Decodable , Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
104
+ #[ derive( Encodable , Decodable , Clone , Debug , PartialEq , Eq , Hash ) ]
106
105
#[ derive( HashStable_Generic ) ]
107
106
pub struct ConstStability {
108
107
pub level : StabilityLevel ,
109
- pub feature : Symbol ,
110
108
/// whether the function has a `#[rustc_promotable]` attribute
111
109
pub promotable : bool ,
112
110
}
113
111
114
112
/// The available stability levels.
115
- #[ derive( Encodable , Decodable , PartialEq , Copy , Clone , Debug , Eq , Hash ) ]
113
+ #[ derive( Encodable , Decodable , PartialEq , Clone , Debug , Eq , Hash ) ]
116
114
#[ derive( HashStable_Generic ) ]
117
115
pub enum StabilityLevel {
118
- // Reason for the current stability level and the relevant rust-lang issue
119
- Unstable { reason : Option < Symbol > , issue : Option < NonZeroU32 > , is_soft : bool } ,
120
- Stable { since : Symbol } ,
116
+ Unstable { unstables : Vec < Unstability > , is_soft : bool } ,
117
+ Stable { feature : Symbol , since : Symbol , span : Span } ,
118
+ }
119
+
120
+ impl StabilityLevel {
121
+ pub fn spans ( & self ) -> Vec < Span > {
122
+ match self {
123
+ StabilityLevel :: Stable { span, .. } => vec ! [ * span] ,
124
+ StabilityLevel :: Unstable { unstables, .. } => {
125
+ unstables. iter ( ) . map ( |u| u. span ) . collect ( )
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ /// An instance of the `#[unstable]` attribute
132
+ #[ derive( Encodable , Decodable , PartialEq , Clone , Debug , Eq , Hash ) ]
133
+ #[ derive( HashStable_Generic ) ]
134
+ pub struct Unstability {
135
+ pub feature : Symbol ,
136
+ pub issue : Option < NonZeroU32 > ,
137
+ pub reason : Option < Symbol > ,
138
+ pub span : Span ,
121
139
}
122
140
123
141
impl StabilityLevel {
124
142
pub fn is_unstable ( & self ) -> bool {
125
143
matches ! ( self , StabilityLevel :: Unstable { .. } )
126
144
}
145
+
127
146
pub fn is_stable ( & self ) -> bool {
128
147
matches ! ( self , StabilityLevel :: Stable { .. } )
129
148
}
149
+
150
+ pub fn has_unstable_feature ( & self , sym : Symbol ) -> bool {
151
+ if let StabilityLevel :: Unstable { unstables, .. } = & self {
152
+ unstables. iter ( ) . any ( |u| u. feature == sym)
153
+ } else {
154
+ false
155
+ }
156
+ }
130
157
}
131
158
132
159
/// Collects stability info from all stability attributes in `attrs`.
@@ -135,22 +162,22 @@ pub fn find_stability(
135
162
sess : & Session ,
136
163
attrs : & [ Attribute ] ,
137
164
item_sp : Span ,
138
- ) -> ( Option < ( Stability , Span ) > , Option < ( ConstStability , Span ) > ) {
165
+ ) -> ( Option < Stability > , Option < ConstStability > ) {
139
166
find_stability_generic ( sess, attrs. iter ( ) , item_sp)
140
167
}
141
168
142
169
fn find_stability_generic < ' a , I > (
143
170
sess : & Session ,
144
171
attrs_iter : I ,
145
172
item_sp : Span ,
146
- ) -> ( Option < ( Stability , Span ) > , Option < ( ConstStability , Span ) > )
173
+ ) -> ( Option < Stability > , Option < ConstStability > )
147
174
where
148
175
I : Iterator < Item = & ' a Attribute > ,
149
176
{
150
177
use StabilityLevel :: * ;
151
178
152
- let mut stab: Option < ( Stability , Span ) > = None ;
153
- let mut const_stab: Option < ( ConstStability , Span ) > = None ;
179
+ let mut stab: Option < Stability > = None ;
180
+ let mut const_stab: Option < ConstStability > = None ;
154
181
let mut promotable = false ;
155
182
156
183
let diagnostic = & sess. parse_sess . span_diagnostic ;
@@ -198,22 +225,6 @@ where
198
225
let meta_name = meta. name_or_empty ( ) ;
199
226
match meta_name {
200
227
sym:: rustc_const_unstable | sym:: unstable => {
201
- if meta_name == sym:: unstable && stab. is_some ( ) {
202
- handle_errors (
203
- & sess. parse_sess ,
204
- attr. span ,
205
- AttrError :: MultipleStabilityLevels ,
206
- ) ;
207
- break ;
208
- } else if meta_name == sym:: rustc_const_unstable && const_stab. is_some ( ) {
209
- handle_errors (
210
- & sess. parse_sess ,
211
- attr. span ,
212
- AttrError :: MultipleStabilityLevels ,
213
- ) ;
214
- break ;
215
- }
216
-
217
228
let mut feature = None ;
218
229
let mut reason = None ;
219
230
let mut issue = None ;
@@ -308,14 +319,70 @@ where
308
319
) ;
309
320
continue ;
310
321
}
311
- let level = Unstable { reason, issue : issue_num, is_soft } ;
322
+ let unstability =
323
+ Unstability { feature, issue : issue_num, reason, span : attr. span } ;
312
324
if sym:: unstable == meta_name {
313
- stab = Some ( ( Stability { level, feature } , attr. span ) ) ;
325
+ match & mut stab {
326
+ stab @ None => {
327
+ * stab = Some ( Stability {
328
+ level : StabilityLevel :: Unstable {
329
+ unstables : vec ! [ unstability] ,
330
+ is_soft,
331
+ } ,
332
+ } )
333
+ }
334
+ // Merge multiple unstability attributes into one
335
+ Some ( Stability {
336
+ level :
337
+ StabilityLevel :: Unstable { unstables, is_soft : old_is_soft } ,
338
+ } ) => {
339
+ unstables. push ( unstability) ;
340
+ // FIXME(compiler-errors): Do we want this behavior: is_soft iff all are is_soft?
341
+ * old_is_soft &= is_soft;
342
+ }
343
+ _ => {
344
+ handle_errors (
345
+ & sess. parse_sess ,
346
+ attr. span ,
347
+ AttrError :: MultipleStabilityLevels ,
348
+ ) ;
349
+ }
350
+ }
314
351
} else {
315
- const_stab = Some ( (
316
- ConstStability { level, feature, promotable : false } ,
317
- attr. span ,
318
- ) ) ;
352
+ match & mut const_stab {
353
+ const_stab @ None => {
354
+ * const_stab = Some ( ConstStability {
355
+ level : StabilityLevel :: Unstable {
356
+ unstables : vec ! [ unstability] ,
357
+ is_soft,
358
+ } ,
359
+ promotable : false ,
360
+ } )
361
+ }
362
+ Some ( ConstStability {
363
+ level :
364
+ StabilityLevel :: Unstable {
365
+ unstables : unstability,
366
+ is_soft : old_is_soft,
367
+ } ,
368
+ ..
369
+ } ) => {
370
+ unstability. push ( Unstability {
371
+ feature,
372
+ issue : issue_num,
373
+ reason,
374
+ span : attr. span ,
375
+ } ) ;
376
+ * old_is_soft &= is_soft;
377
+ }
378
+ _ => {
379
+ handle_errors (
380
+ & sess. parse_sess ,
381
+ attr. span ,
382
+ AttrError :: MultipleStabilityLevels ,
383
+ ) ;
384
+ }
385
+ }
319
386
}
320
387
}
321
388
( None , _, _) => {
@@ -386,14 +453,11 @@ where
386
453
387
454
match ( feature, since) {
388
455
( Some ( feature) , Some ( since) ) => {
389
- let level = Stable { since } ;
456
+ let level = Stable { since, feature , span : attr . span } ;
390
457
if sym:: stable == meta_name {
391
- stab = Some ( ( Stability { level, feature } , attr . span ) ) ;
458
+ stab = Some ( Stability { level } ) ;
392
459
} else {
393
- const_stab = Some ( (
394
- ConstStability { level, feature, promotable : false } ,
395
- attr. span ,
396
- ) ) ;
460
+ const_stab = Some ( ConstStability { level, promotable : false } ) ;
397
461
}
398
462
}
399
463
( None , _) => {
@@ -413,7 +477,7 @@ where
413
477
414
478
// Merge the const-unstable info into the stability info
415
479
if promotable {
416
- if let Some ( ( ref mut stab, _ ) ) = const_stab {
480
+ if let Some ( stab) = & mut const_stab {
417
481
stab. promotable = promotable;
418
482
} else {
419
483
struct_span_err ! (
0 commit comments