12
12
//! propagating default levels lexically from parent to children ast nodes.
13
13
14
14
pub use self :: StabilityLevel :: * ;
15
+ use self :: AnnotationKind :: * ;
15
16
16
17
use session:: Session ;
17
18
use lint;
@@ -30,8 +31,8 @@ use syntax::attr::{self, Stability, AttrMetaMethods};
30
31
use util:: nodemap:: { DefIdMap , FnvHashSet , FnvHashMap } ;
31
32
32
33
use rustc_front:: hir;
33
- use rustc_front:: hir:: { FnDecl , Block , Crate , Item , Generics , StructField , Variant } ;
34
- use rustc_front:: visit:: { self , FnKind , Visitor } ;
34
+ use rustc_front:: hir:: { Block , Crate , Item , Generics , StructField , Variant } ;
35
+ use rustc_front:: visit:: { self , Visitor } ;
35
36
36
37
use std:: mem:: replace;
37
38
use std:: cmp:: Ordering ;
@@ -48,6 +49,16 @@ impl StabilityLevel {
48
49
}
49
50
}
50
51
52
+ #[ derive( PartialEq ) ]
53
+ enum AnnotationKind {
54
+ // Annotation is required if not inherited from unstable parents
55
+ AnnRequired ,
56
+ // Annotation is useless, reject it
57
+ AnnProhibited ,
58
+ // Annotation itself is useless, but it can be propagated to children
59
+ AnnContainer ,
60
+ }
61
+
51
62
/// A stability index, giving the stability level for items and methods.
52
63
pub struct Index < ' tcx > {
53
64
/// This is mostly a cache, except the stabilities of local items
@@ -64,174 +75,180 @@ struct Annotator<'a, 'tcx: 'a> {
64
75
index : & ' a mut Index < ' tcx > ,
65
76
parent : Option < & ' tcx Stability > ,
66
77
export_map : & ' a PublicItems ,
78
+ in_trait_impl : bool ,
79
+ in_enum : bool ,
67
80
}
68
81
69
82
impl < ' a , ' tcx : ' a > Annotator < ' a , ' tcx > {
70
83
// Determine the stability for a node based on its attributes and inherited
71
84
// stability. The stability is recorded in the index and used as the parent.
72
- fn annotate < F > ( & mut self , id : NodeId , use_parent : bool ,
73
- attrs : & Vec < Attribute > , item_sp : Span , f : F , required : bool ) where
74
- F : FnOnce ( & mut Annotator ) ,
85
+ fn annotate < F > ( & mut self , id : NodeId , attrs : & Vec < Attribute > ,
86
+ item_sp : Span , kind : AnnotationKind , visit_children : F )
87
+ where F : FnOnce ( & mut Annotator )
75
88
{
76
89
if self . index . staged_api [ & LOCAL_CRATE ] {
77
90
debug ! ( "annotate(id = {:?}, attrs = {:?})" , id, attrs) ;
78
- match attr:: find_stability ( self . tcx . sess . diagnostic ( ) , attrs, item_sp) {
79
- Some ( mut stab) => {
80
- debug ! ( "annotate: found {:?}" , stab) ;
81
- // if parent is deprecated and we're not, inherit this by merging
82
- // deprecated_since and its reason.
83
- if let Some ( parent_stab) = self . parent {
84
- if parent_stab. depr . is_some ( )
85
- && stab. depr . is_none ( ) {
86
- stab. depr = parent_stab. depr . clone ( )
87
- }
91
+ if let Some ( mut stab) = attr:: find_stability ( self . tcx . sess . diagnostic ( ) ,
92
+ attrs, item_sp) {
93
+ // Error if prohibited, or can't inherit anything from a container
94
+ if kind == AnnProhibited ||
95
+ kind == AnnContainer && stab. level . is_stable ( ) && stab. depr . is_none ( ) {
96
+ self . tcx . sess . span_err ( item_sp, "This stability annotation is useless" ) ;
97
+ }
98
+
99
+ debug ! ( "annotate: found {:?}" , stab) ;
100
+ // If parent is deprecated and we're not, inherit this by merging
101
+ // deprecated_since and its reason.
102
+ if let Some ( parent_stab) = self . parent {
103
+ if parent_stab. depr . is_some ( ) && stab. depr . is_none ( ) {
104
+ stab. depr = parent_stab. depr . clone ( )
88
105
}
106
+ }
89
107
90
- let stab = self . tcx . intern_stability ( stab) ;
91
-
92
- // Check if deprecated_since < stable_since. If it is,
93
- // this is *almost surely* an accident.
94
- let deprecated_predates_stable = match ( & stab. depr , & stab. level ) {
95
- ( & Some ( attr:: Deprecation { since : ref dep_since, ..} ) ,
96
- & attr:: Stable { since : ref stab_since} ) => {
97
- // explicit version of iter::order::lt to handle parse errors properly
98
- let mut is_less = false ;
99
- for ( dep_v, stab_v) in dep_since. split ( "." ) . zip ( stab_since. split ( "." ) ) {
100
- match ( dep_v. parse :: < u64 > ( ) , stab_v. parse :: < u64 > ( ) ) {
101
- ( Ok ( dep_v) , Ok ( stab_v) ) => match dep_v. cmp ( & stab_v) {
102
- Ordering :: Less => {
103
- is_less = true ;
104
- break ;
105
- }
106
- Ordering :: Equal => { continue ; }
107
- Ordering :: Greater => { break ; }
108
- } ,
109
- _ => {
110
- self . tcx . sess . span_err ( item_sp,
111
- "Invalid stability or deprecation version found" ) ;
112
- // act like it isn't less because the question is now
113
- // nonsensical, and this makes us not do anything else
114
- // interesting.
115
- break ;
116
- }
108
+ let stab = self . tcx . intern_stability ( stab) ;
109
+
110
+ // Check if deprecated_since < stable_since. If it is,
111
+ // this is *almost surely* an accident.
112
+ if let ( & Some ( attr:: Deprecation { since : ref dep_since, ..} ) ,
113
+ & attr:: Stable { since : ref stab_since} ) = ( & stab. depr , & stab. level ) {
114
+ // Explicit version of iter::order::lt to handle parse errors properly
115
+ for ( dep_v, stab_v) in dep_since. split ( "." ) . zip ( stab_since. split ( "." ) ) {
116
+ if let ( Ok ( dep_v) , Ok ( stab_v) ) = ( dep_v. parse :: < u64 > ( ) , stab_v. parse ( ) ) {
117
+ match dep_v. cmp ( & stab_v) {
118
+ Ordering :: Less => {
119
+ self . tcx . sess . span_err ( item_sp, "An API can't be stabilized \
120
+ after it is deprecated") ;
121
+ break
117
122
}
123
+ Ordering :: Equal => continue ,
124
+ Ordering :: Greater => break ,
118
125
}
119
- is_less
120
- } ,
121
- _ => false ,
122
- } ;
123
-
124
- if deprecated_predates_stable {
125
- self . tcx . sess . span_err ( item_sp,
126
- "An API can't be stabilized after it is deprecated" ) ;
126
+ } else {
127
+ // Act like it isn't less because the question is now nonsensical,
128
+ // and this makes us not do anything else interesting.
129
+ self . tcx . sess . span_err ( item_sp, "Invalid stability or deprecation \
130
+ version found") ;
131
+ break
132
+ }
127
133
}
134
+ }
128
135
129
- let def_id = self . tcx . map . local_def_id ( id) ;
130
- self . index . map . insert ( def_id, Some ( stab) ) ;
131
-
132
- // Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
133
- if !stab. level . is_stable ( ) {
134
- let parent = replace ( & mut self . parent , Some ( stab) ) ;
135
- f ( self ) ;
136
- self . parent = parent;
137
- } else {
138
- f ( self ) ;
136
+ let def_id = self . tcx . map . local_def_id ( id) ;
137
+ self . index . map . insert ( def_id, Some ( stab) ) ;
138
+
139
+ let parent = replace ( & mut self . parent , Some ( stab) ) ;
140
+ visit_children ( self ) ;
141
+ self . parent = parent;
142
+ } else {
143
+ debug ! ( "annotate: not found, parent = {:?}" , self . parent) ;
144
+ let mut is_error = kind == AnnRequired &&
145
+ self . export_map . contains ( & id) &&
146
+ !self . tcx . sess . opts . test ;
147
+ if let Some ( stab) = self . parent {
148
+ if stab. level . is_unstable ( ) {
149
+ let def_id = self . tcx . map . local_def_id ( id) ;
150
+ self . index . map . insert ( def_id, Some ( stab) ) ;
151
+ is_error = false ;
139
152
}
140
153
}
141
- None => {
142
- debug ! ( "annotate: not found, use_parent = {:?}, parent = {:?}" ,
143
- use_parent, self . parent) ;
144
- if use_parent {
145
- if let Some ( stab) = self . parent {
146
- let def_id = self . tcx . map . local_def_id ( id) ;
147
- self . index . map . insert ( def_id, Some ( stab) ) ;
148
- } else if self . index . staged_api [ & LOCAL_CRATE ] && required
149
- && self . export_map . contains ( & id)
150
- && !self . tcx . sess . opts . test {
151
- self . tcx . sess . span_err ( item_sp,
152
- "This node does not \
153
- have a stability attribute") ;
154
- }
155
- }
156
- f ( self ) ;
154
+ if is_error {
155
+ self . tcx . sess . span_err ( item_sp, "This node does not have \
156
+ a stability attribute") ;
157
157
}
158
+ visit_children ( self ) ;
158
159
}
159
160
} else {
160
- // Emit warnings for non-staged-api crates. These should be errors .
161
+ // Emit errors for non-staged-api crates.
161
162
for attr in attrs {
162
163
let tag = attr. name ( ) ;
163
164
if tag == "unstable" || tag == "stable" || tag == "deprecated" {
164
165
attr:: mark_used ( attr) ;
165
- self . tcx . sess . span_err ( attr. span ( ) ,
166
- "stability attributes may not be used outside \
167
- of the standard library") ;
166
+ self . tcx . sess . span_err ( attr. span ( ) , "stability attributes may not be used \
167
+ outside of the standard library") ;
168
168
}
169
169
}
170
- f ( self ) ;
170
+ visit_children ( self ) ;
171
171
}
172
172
}
173
173
}
174
174
175
175
impl < ' a , ' tcx , ' v > Visitor < ' v > for Annotator < ' a , ' tcx > {
176
176
fn visit_item ( & mut self , i : & Item ) {
177
- // FIXME (#18969): the following is a hack around the fact
178
- // that we cannot currently annotate the stability of
179
- // `deriving`. Basically, we do *not* allow stability
180
- // inheritance on trait implementations, so that derived
181
- // implementations appear to be unannotated. This then allows
182
- // derived implementations to be automatically tagged with the
183
- // stability of the trait. This is WRONG, but expedient to get
184
- // libstd stabilized for the 1.0 release.
185
- let use_parent = match i. node {
186
- hir:: ItemImpl ( _, _, _, Some ( _) , _, _) => false ,
187
- _ => true ,
188
- } ;
189
-
190
- // In case of a `pub use <mod>;`, we should not error since the stability
191
- // is inherited from the module itself
192
- let required = match i. node {
193
- hir:: ItemUse ( _) => i. vis != hir:: Public ,
194
- _ => true
195
- } ;
196
-
197
- self . annotate ( i. id , use_parent, & i. attrs , i. span ,
198
- |v| visit:: walk_item ( v, i) , required) ;
199
-
200
- if let hir:: ItemStruct ( ref sd, _) = i. node {
201
- if !sd. is_struct ( ) {
202
- self . annotate ( sd. id ( ) , true , & i. attrs , i. span , |_| { } , true )
177
+ let orig_in_trait_impl = self . in_trait_impl ;
178
+ let orig_in_enum = self . in_enum ;
179
+ let mut kind = AnnRequired ;
180
+ match i. node {
181
+ // Inherent impls and foreign modules serve only as containers for other items,
182
+ // they don't have their own stability. They still can be annotated as unstable
183
+ // and propagate this unstability to children, but this annotation is completely
184
+ // optional. They inherit stability from their parents when unannotated.
185
+ hir:: ItemImpl ( _, _, _, None , _, _) | hir:: ItemForeignMod ( ..) => {
186
+ self . in_trait_impl = false ;
187
+ kind = AnnContainer ;
188
+ }
189
+ hir:: ItemImpl ( _, _, _, Some ( _) , _, _) => {
190
+ self . in_trait_impl = true ;
191
+ }
192
+ hir:: ItemStruct ( ref sd, _) => {
193
+ self . in_enum = false ;
194
+ if !sd. is_struct ( ) {
195
+ self . annotate ( sd. id ( ) , & i. attrs , i. span , AnnRequired , |_| { } )
196
+ }
197
+ }
198
+ hir:: ItemEnum ( ..) => {
199
+ self . in_enum = true ;
203
200
}
201
+ _ => { }
204
202
}
205
- }
206
203
207
- fn visit_fn ( & mut self , _: FnKind < ' v > , _: & ' v FnDecl ,
208
- _: & ' v Block , _: Span , _: NodeId ) {
209
- // Items defined in a function body have no reason to have
210
- // a stability attribute, so we don't recurse.
204
+ self . annotate ( i. id , & i. attrs , i. span , kind, |v| {
205
+ visit:: walk_item ( v, i)
206
+ } ) ;
207
+ self . in_trait_impl = orig_in_trait_impl;
208
+ self . in_enum = orig_in_enum;
211
209
}
212
210
213
211
fn visit_trait_item ( & mut self , ti : & hir:: TraitItem ) {
214
- self . annotate ( ti. id , true , & ti. attrs , ti. span ,
215
- |v| visit:: walk_trait_item ( v, ti) , true ) ;
212
+ self . annotate ( ti. id , & ti. attrs , ti. span , AnnRequired , |v| {
213
+ visit:: walk_trait_item ( v, ti) ;
214
+ } ) ;
216
215
}
217
216
218
217
fn visit_impl_item ( & mut self , ii : & hir:: ImplItem ) {
219
- self . annotate ( ii. id , true , & ii. attrs , ii. span ,
220
- |v| visit:: walk_impl_item ( v, ii) , false ) ;
218
+ let kind = if self . in_trait_impl { AnnProhibited } else { AnnRequired } ;
219
+ self . annotate ( ii. id , & ii. attrs , ii. span , kind, |v| {
220
+ visit:: walk_impl_item ( v, ii) ;
221
+ } ) ;
221
222
}
222
223
223
224
fn visit_variant ( & mut self , var : & Variant , g : & ' v Generics , item_id : NodeId ) {
224
- self . annotate ( var. node . data . id ( ) , true , & var. node . attrs , var. span ,
225
- |v| visit:: walk_variant ( v, var, g, item_id) , true )
225
+ self . annotate ( var. node . data . id ( ) , & var. node . attrs , var. span , AnnRequired , |v| {
226
+ visit:: walk_variant ( v, var, g, item_id) ;
227
+ } )
226
228
}
227
229
228
230
fn visit_struct_field ( & mut self , s : & StructField ) {
229
- self . annotate ( s. node . id , true , & s. node . attrs , s. span ,
230
- |v| visit:: walk_struct_field ( v, s) , !s. node . kind . is_unnamed ( ) ) ;
231
+ // FIXME: This is temporary, can't use attributes with tuple variant fields until snapshot
232
+ let kind = if self . in_enum && s. node . kind . is_unnamed ( ) {
233
+ AnnProhibited
234
+ } else {
235
+ AnnRequired
236
+ } ;
237
+ self . annotate ( s. node . id , & s. node . attrs , s. span , kind, |v| {
238
+ visit:: walk_struct_field ( v, s) ;
239
+ } ) ;
231
240
}
232
241
233
242
fn visit_foreign_item ( & mut self , i : & hir:: ForeignItem ) {
234
- self . annotate ( i. id , true , & i. attrs , i. span , |_| { } , true ) ;
243
+ self . annotate ( i. id , & i. attrs , i. span , AnnRequired , |v| {
244
+ visit:: walk_foreign_item ( v, i) ;
245
+ } ) ;
246
+ }
247
+
248
+ fn visit_macro_def ( & mut self , md : & ' v hir:: MacroDef ) {
249
+ if md. imported_from . is_none ( ) {
250
+ self . annotate ( md. id , & md. attrs , md. span , AnnRequired , |_| { } ) ;
251
+ }
235
252
}
236
253
}
237
254
@@ -243,21 +260,21 @@ impl<'tcx> Index<'tcx> {
243
260
index : self ,
244
261
parent : None ,
245
262
export_map : export_map,
263
+ in_trait_impl : false ,
264
+ in_enum : false ,
246
265
} ;
247
- annotator. annotate ( ast:: CRATE_NODE_ID , true , & krate. attrs , krate. span ,
248
- |v| visit:: walk_crate ( v, krate) , true ) ;
266
+ annotator. annotate ( ast:: CRATE_NODE_ID , & krate. attrs , krate. span , AnnRequired ,
267
+ |v| visit:: walk_crate ( v, krate) ) ;
249
268
}
250
269
251
270
pub fn new ( krate : & Crate ) -> Index {
252
271
let mut is_staged_api = false ;
253
272
for attr in & krate. attrs {
254
- if & attr. name ( ) [ ..] == "staged_api" {
255
- match attr. node . value . node {
256
- ast:: MetaWord ( _) => {
257
- attr:: mark_used ( attr) ;
258
- is_staged_api = true ;
259
- }
260
- _ => ( /*pass*/ )
273
+ if attr. name ( ) == "staged_api" {
274
+ if let ast:: MetaWord ( _) = attr. node . value . node {
275
+ attr:: mark_used ( attr) ;
276
+ is_staged_api = true ;
277
+ break
261
278
}
262
279
}
263
280
}
0 commit comments