@@ -94,39 +94,66 @@ pub enum OptimizeAttr {
9494///
9595/// - `#[stable]`
9696/// - `#[unstable]`
97- #[ derive( Encodable , Decodable , Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
97+ #[ derive( Encodable , Decodable , Clone , Debug , PartialEq , Eq , Hash ) ]
9898#[ derive( HashStable_Generic ) ]
9999pub struct Stability {
100100 pub level : StabilityLevel ,
101- pub feature : Symbol ,
102101}
103102
104103/// 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 ) ]
106105#[ derive( HashStable_Generic ) ]
107106pub struct ConstStability {
108107 pub level : StabilityLevel ,
109- pub feature : Symbol ,
110108 /// whether the function has a `#[rustc_promotable]` attribute
111109 pub promotable : bool ,
112110}
113111
114112/// The available stability levels.
115- #[ derive( Encodable , Decodable , PartialEq , Copy , Clone , Debug , Eq , Hash ) ]
113+ #[ derive( Encodable , Decodable , PartialEq , Clone , Debug , Eq , Hash ) ]
116114#[ derive( HashStable_Generic ) ]
117115pub 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 ,
121139}
122140
123141impl StabilityLevel {
124142 pub fn is_unstable ( & self ) -> bool {
125143 matches ! ( self , StabilityLevel :: Unstable { .. } )
126144 }
145+
127146 pub fn is_stable ( & self ) -> bool {
128147 matches ! ( self , StabilityLevel :: Stable { .. } )
129148 }
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+ }
130157}
131158
132159/// Collects stability info from all stability attributes in `attrs`.
@@ -135,22 +162,22 @@ pub fn find_stability(
135162 sess : & Session ,
136163 attrs : & [ Attribute ] ,
137164 item_sp : Span ,
138- ) -> ( Option < ( Stability , Span ) > , Option < ( ConstStability , Span ) > ) {
165+ ) -> ( Option < Stability > , Option < ConstStability > ) {
139166 find_stability_generic ( sess, attrs. iter ( ) , item_sp)
140167}
141168
142169fn find_stability_generic < ' a , I > (
143170 sess : & Session ,
144171 attrs_iter : I ,
145172 item_sp : Span ,
146- ) -> ( Option < ( Stability , Span ) > , Option < ( ConstStability , Span ) > )
173+ ) -> ( Option < Stability > , Option < ConstStability > )
147174where
148175 I : Iterator < Item = & ' a Attribute > ,
149176{
150177 use StabilityLevel :: * ;
151178
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 ;
154181 let mut promotable = false ;
155182
156183 let diagnostic = & sess. parse_sess . span_diagnostic ;
@@ -198,22 +225,6 @@ where
198225 let meta_name = meta. name_or_empty ( ) ;
199226 match meta_name {
200227 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-
217228 let mut feature = None ;
218229 let mut reason = None ;
219230 let mut issue = None ;
@@ -308,14 +319,70 @@ where
308319 ) ;
309320 continue ;
310321 }
311- let level = Unstable { reason, issue : issue_num, is_soft } ;
322+ let unstability =
323+ Unstability { feature, issue : issue_num, reason, span : attr. span } ;
312324 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+ }
314351 } 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+ }
319386 }
320387 }
321388 ( None , _, _) => {
@@ -386,14 +453,11 @@ where
386453
387454 match ( feature, since) {
388455 ( Some ( feature) , Some ( since) ) => {
389- let level = Stable { since } ;
456+ let level = Stable { since, feature , span : attr . span } ;
390457 if sym:: stable == meta_name {
391- stab = Some ( ( Stability { level, feature } , attr . span ) ) ;
458+ stab = Some ( Stability { level } ) ;
392459 } else {
393- const_stab = Some ( (
394- ConstStability { level, feature, promotable : false } ,
395- attr. span ,
396- ) ) ;
460+ const_stab = Some ( ConstStability { level, promotable : false } ) ;
397461 }
398462 }
399463 ( None , _) => {
@@ -413,7 +477,7 @@ where
413477
414478 // Merge the const-unstable info into the stability info
415479 if promotable {
416- if let Some ( ( ref mut stab, _ ) ) = const_stab {
480+ if let Some ( stab) = & mut const_stab {
417481 stab. promotable = promotable;
418482 } else {
419483 struct_span_err ! (
0 commit comments