1
1
use super :: { active:: { ACTIVE_FEATURES , Features } , Feature , State as FeatureState } ;
2
2
use super :: accepted:: ACCEPTED_FEATURES ;
3
3
use super :: removed:: { REMOVED_FEATURES , STABLE_REMOVED_FEATURES } ;
4
- use super :: builtin_attrs:: { AttributeGate , AttributeType , BuiltinAttribute , BUILTIN_ATTRIBUTE_MAP } ;
4
+ use super :: builtin_attrs:: { AttributeGate , BUILTIN_ATTRIBUTE_MAP } ;
5
5
6
6
use crate :: ast:: {
7
7
self , AssocTyConstraint , AssocTyConstraintKind , NodeId , GenericParam , GenericParamKind ,
@@ -32,16 +32,10 @@ pub enum Stability {
32
32
Deprecated ( & ' static str , Option < & ' static str > ) ,
33
33
}
34
34
35
- struct Context < ' a > {
36
- features : & ' a Features ,
37
- parse_sess : & ' a ParseSess ,
38
- plugin_attributes : & ' a [ ( Symbol , AttributeType ) ] ,
39
- }
40
-
41
35
macro_rules! gate_feature_fn {
42
36
( $cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => { {
43
37
let ( cx, has_feature, span,
44
- name, explain, level) = ( $cx, $has_feature, $span, $name, $explain, $level) ;
38
+ name, explain, level) = ( & * $cx, $has_feature, $span, $name, $explain, $level) ;
45
39
let has_feature: bool = has_feature( & $cx. features) ;
46
40
debug!( "gate_feature(feature = {:?}, span = {:?}); has? {}" , name, span, has_feature) ;
47
41
if !has_feature && !span. allows_unstable( $name) {
@@ -62,68 +56,8 @@ macro_rules! gate_feature {
62
56
} ;
63
57
}
64
58
65
- impl < ' a > Context < ' a > {
66
- fn check_attribute (
67
- & self ,
68
- attr : & ast:: Attribute ,
69
- attr_info : Option < & BuiltinAttribute > ,
70
- is_macro : bool
71
- ) {
72
- debug ! ( "check_attribute(attr = {:?})" , attr) ;
73
- if let Some ( & ( name, ty, _template, ref gateage) ) = attr_info {
74
- if let AttributeGate :: Gated ( _, name, desc, ref has_feature) = * gateage {
75
- if !attr. span . allows_unstable ( name) {
76
- gate_feature_fn ! (
77
- self , has_feature, attr. span, name, desc, GateStrength :: Hard
78
- ) ;
79
- }
80
- } else if name == sym:: doc {
81
- if let Some ( content) = attr. meta_item_list ( ) {
82
- if content. iter ( ) . any ( |c| c. check_name ( sym:: include) ) {
83
- gate_feature ! ( self , external_doc, attr. span,
84
- "`#[doc(include = \" ...\" )]` is experimental"
85
- ) ;
86
- }
87
- }
88
- }
89
- debug ! ( "check_attribute: {:?} is builtin, {:?}, {:?}" , attr. path, ty, gateage) ;
90
- return ;
91
- } else {
92
- for segment in & attr. path . segments {
93
- if segment. ident . as_str ( ) . starts_with ( "rustc" ) {
94
- let msg = "attributes starting with `rustc` are \
95
- reserved for use by the `rustc` compiler";
96
- gate_feature ! ( self , rustc_attrs, segment. ident. span, msg) ;
97
- }
98
- }
99
- }
100
- for & ( n, ty) in self . plugin_attributes {
101
- if attr. path == n {
102
- // Plugins can't gate attributes, so we don't check for it
103
- // unlike the code above; we only use this loop to
104
- // short-circuit to avoid the checks below.
105
- debug ! ( "check_attribute: {:?} is registered by a plugin, {:?}" , attr. path, ty) ;
106
- return ;
107
- }
108
- }
109
- if !is_macro && !attr:: is_known ( attr) {
110
- // Only run the custom attribute lint during regular feature gate
111
- // checking. Macro gating runs before the plugin attributes are
112
- // registered, so we skip this in that case.
113
- let msg = format ! ( "the attribute `{}` is currently unknown to the compiler and \
114
- may have meaning added to it in the future", attr. path) ;
115
- gate_feature ! ( self , custom_attribute, attr. span, & msg) ;
116
- }
117
- }
118
- }
119
-
120
- pub fn check_attribute ( attr : & ast:: Attribute , parse_sess : & ParseSess , features : & Features ) {
121
- let cx = Context { features, parse_sess, plugin_attributes : & [ ] } ;
122
- cx. check_attribute (
123
- attr,
124
- attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) . map ( |a| * a) ) ,
125
- true
126
- ) ;
59
+ crate fn check_attribute ( attr : & ast:: Attribute , parse_sess : & ParseSess , features : & Features ) {
60
+ PostExpansionVisitor { parse_sess, features } . visit_attribute ( attr)
127
61
}
128
62
129
63
fn find_lang_feature_issue ( feature : Symbol ) -> Option < u32 > {
@@ -238,21 +172,21 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
238
172
"unsized tuple coercion is not stable enough for use and is subject to change" ;
239
173
240
174
struct PostExpansionVisitor < ' a > {
241
- context : & ' a Context < ' a > ,
242
- builtin_attributes : & ' static FxHashMap < Symbol , & ' static BuiltinAttribute > ,
175
+ parse_sess : & ' a ParseSess ,
176
+ features : & ' a Features ,
243
177
}
244
178
245
179
macro_rules! gate_feature_post {
246
180
( $cx: expr, $feature: ident, $span: expr, $explain: expr) => { {
247
181
let ( cx, span) = ( $cx, $span) ;
248
182
if !span. allows_unstable( sym:: $feature) {
249
- gate_feature!( cx. context , $feature, span, $explain)
183
+ gate_feature!( cx, $feature, span, $explain)
250
184
}
251
185
} } ;
252
186
( $cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { {
253
187
let ( cx, span) = ( $cx, $span) ;
254
188
if !span. allows_unstable( sym:: $feature) {
255
- gate_feature!( cx. context , $feature, span, $explain, $level)
189
+ gate_feature!( cx, $feature, span, $explain, $level)
256
190
}
257
191
} }
258
192
}
@@ -316,58 +250,52 @@ impl<'a> PostExpansionVisitor<'a> {
316
250
317
251
impl < ' a > Visitor < ' a > for PostExpansionVisitor < ' a > {
318
252
fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
319
- let attr_info = attr. ident ( ) . and_then ( |ident| {
320
- self . builtin_attributes . get ( & ident. name ) . map ( |a| * a)
321
- } ) ;
322
-
323
- // Check for gated attributes.
324
- self . context . check_attribute ( attr, attr_info, false ) ;
325
-
326
- if attr. check_name ( sym:: doc) {
327
- if let Some ( content) = attr. meta_item_list ( ) {
328
- if content. len ( ) == 1 && content[ 0 ] . check_name ( sym:: cfg) {
329
- gate_feature_post ! ( & self , doc_cfg, attr. span,
330
- "`#[doc(cfg(...))]` is experimental"
331
- ) ;
332
- } else if content. iter ( ) . any ( |c| c. check_name ( sym:: masked) ) {
333
- gate_feature_post ! ( & self , doc_masked, attr. span,
334
- "`#[doc(masked)]` is experimental"
335
- ) ;
336
- } else if content. iter ( ) . any ( |c| c. check_name ( sym:: spotlight) ) {
337
- gate_feature_post ! ( & self , doc_spotlight, attr. span,
338
- "`#[doc(spotlight)]` is experimental"
339
- ) ;
340
- } else if content. iter ( ) . any ( |c| c. check_name ( sym:: alias) ) {
341
- gate_feature_post ! ( & self , doc_alias, attr. span,
342
- "`#[doc(alias = \" ...\" )]` is experimental"
343
- ) ;
344
- } else if content. iter ( ) . any ( |c| c. check_name ( sym:: keyword) ) {
345
- gate_feature_post ! ( & self , doc_keyword, attr. span,
346
- "`#[doc(keyword = \" ...\" )]` is experimental"
347
- ) ;
348
- }
349
- }
253
+ let attr_info =
254
+ attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) . map ( |a| * * a) ;
255
+ // Check feature gates for built-in attributes.
256
+ if let Some ( ( .., AttributeGate :: Gated ( _, name, descr, has_feature) ) ) = attr_info {
257
+ gate_feature_fn ! ( self , has_feature, attr. span, name, descr, GateStrength :: Hard ) ;
350
258
}
351
-
259
+ // Check input tokens for built-in and key-value attributes.
352
260
match attr_info {
353
261
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
354
- Some ( & ( name, _, template, _) ) if name != sym:: rustc_dummy =>
355
- check_builtin_attribute ( self . context . parse_sess , attr, name, template) ,
262
+ Some ( ( name, _, template, _) ) if name != sym:: rustc_dummy =>
263
+ check_builtin_attribute ( self . parse_sess , attr, name, template) ,
356
264
_ => if let Some ( TokenTree :: Token ( token) ) = attr. tokens . trees ( ) . next ( ) {
357
265
if token == token:: Eq {
358
266
// All key-value attributes are restricted to meta-item syntax.
359
- attr. parse_meta ( self . context . parse_sess ) . map_err ( |mut err| err. emit ( ) ) . ok ( ) ;
267
+ attr. parse_meta ( self . parse_sess ) . map_err ( |mut err| err. emit ( ) ) . ok ( ) ;
360
268
}
361
269
}
362
270
}
271
+ // Check unstable flavors of the `#[doc]` attribute.
272
+ if attr. check_name ( sym:: doc) {
273
+ for nested_meta in attr. meta_item_list ( ) . unwrap_or_default ( ) {
274
+ macro_rules! gate_doc { ( $( $name: ident => $feature: ident) * ) => {
275
+ $( if nested_meta. check_name( sym:: $name) {
276
+ let msg = concat!( "`#[doc(" , stringify!( $name) , ")]` is experimental" ) ;
277
+ gate_feature!( self , $feature, attr. span, msg) ;
278
+ } ) *
279
+ } }
280
+
281
+ gate_doc ! (
282
+ include => external_doc
283
+ cfg => doc_cfg
284
+ masked => doc_masked
285
+ spotlight => doc_spotlight
286
+ alias => doc_alias
287
+ keyword => doc_keyword
288
+ ) ;
289
+ }
290
+ }
363
291
}
364
292
365
293
fn visit_name ( & mut self , sp : Span , name : ast:: Name ) {
366
294
if !name. as_str ( ) . is_ascii ( ) {
367
295
gate_feature_post ! (
368
296
& self ,
369
297
non_ascii_idents,
370
- self . context . parse_sess. source_map( ) . def_span( sp) ,
298
+ self . parse_sess. source_map( ) . def_span( sp) ,
371
299
"non-ascii idents are not fully supported"
372
300
) ;
373
301
}
@@ -423,12 +351,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
423
351
}
424
352
}
425
353
426
- let has_feature = self . context . features . arbitrary_enum_discriminant ;
354
+ let has_feature = self . features . arbitrary_enum_discriminant ;
427
355
if !has_feature && !i. span . allows_unstable ( sym:: arbitrary_enum_discriminant) {
428
- Parser :: maybe_report_invalid_custom_discriminants (
429
- self . context . parse_sess ,
430
- & variants,
431
- ) ;
356
+ Parser :: maybe_report_invalid_custom_discriminants ( self . parse_sess , & variants) ;
432
357
}
433
358
}
434
359
@@ -538,7 +463,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
538
463
ast:: ExprKind :: Type ( ..) => {
539
464
// To avoid noise about type ascription in common syntax errors, only emit if it
540
465
// is the *only* error.
541
- if self . context . parse_sess . span_diagnostic . err_count ( ) == 0 {
466
+ if self . parse_sess . span_diagnostic . err_count ( ) == 0 {
542
467
gate_feature_post ! ( & self , type_ascription, e. span,
543
468
"type ascription is experimental" ) ;
544
469
}
@@ -872,22 +797,17 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item=&'static Featur
872
797
}
873
798
874
799
pub fn check_crate ( krate : & ast:: Crate ,
875
- sess : & ParseSess ,
800
+ parse_sess : & ParseSess ,
876
801
features : & Features ,
877
- plugin_attributes : & [ ( Symbol , AttributeType ) ] ,
878
802
unstable : UnstableFeatures ) {
879
- maybe_stage_features ( & sess. span_diagnostic , krate, unstable) ;
880
- let ctx = Context {
881
- features,
882
- parse_sess : sess,
883
- plugin_attributes,
884
- } ;
803
+ maybe_stage_features ( & parse_sess. span_diagnostic , krate, unstable) ;
804
+ let mut visitor = PostExpansionVisitor { parse_sess, features } ;
885
805
886
806
macro_rules! gate_all {
887
807
( $gate: ident, $msg: literal) => { gate_all!( $gate, $gate, $msg) ; } ;
888
808
( $spans: ident, $gate: ident, $msg: literal) => {
889
- for span in & * sess . gated_spans. $spans. borrow( ) {
890
- gate_feature!( & ctx , $gate, * span, $msg) ;
809
+ for span in & * parse_sess . gated_spans. $spans. borrow( ) {
810
+ gate_feature!( & visitor , $gate, * span, $msg) ;
891
811
}
892
812
}
893
813
}
@@ -898,11 +818,7 @@ pub fn check_crate(krate: &ast::Crate,
898
818
gate_all ! ( yields, generators, "yield syntax is experimental" ) ;
899
819
gate_all ! ( or_patterns, "or-patterns syntax is experimental" ) ;
900
820
901
- let visitor = & mut PostExpansionVisitor {
902
- context : & ctx,
903
- builtin_attributes : & * BUILTIN_ATTRIBUTE_MAP ,
904
- } ;
905
- visit:: walk_crate ( visitor, krate) ;
821
+ visit:: walk_crate ( & mut visitor, krate) ;
906
822
}
907
823
908
824
#[ derive( Clone , Copy , Hash ) ]
0 commit comments