11use super :: { active:: { ACTIVE_FEATURES , Features } , Feature , State as FeatureState } ;
22use super :: accepted:: ACCEPTED_FEATURES ;
33use 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 } ;
55
66use crate :: ast:: {
77 self , AssocTyConstraint , AssocTyConstraintKind , NodeId , GenericParam , GenericParamKind ,
@@ -32,16 +32,10 @@ pub enum Stability {
3232 Deprecated ( & ' static str , Option < & ' static str > ) ,
3333}
3434
35- struct Context < ' a > {
36- features : & ' a Features ,
37- parse_sess : & ' a ParseSess ,
38- plugin_attributes : & ' a [ ( Symbol , AttributeType ) ] ,
39- }
40-
4135macro_rules! gate_feature_fn {
4236 ( $cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => { {
4337 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) ;
4539 let has_feature: bool = has_feature( & $cx. features) ;
4640 debug!( "gate_feature(feature = {:?}, span = {:?}); has? {}" , name, span, has_feature) ;
4741 if !has_feature && !span. allows_unstable( $name) {
@@ -62,68 +56,8 @@ macro_rules! gate_feature {
6256 } ;
6357}
6458
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)
12761}
12862
12963fn find_lang_feature_issue ( feature : Symbol ) -> Option < u32 > {
@@ -238,21 +172,21 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
238172 "unsized tuple coercion is not stable enough for use and is subject to change" ;
239173
240174struct PostExpansionVisitor < ' a > {
241- context : & ' a Context < ' a > ,
242- builtin_attributes : & ' static FxHashMap < Symbol , & ' static BuiltinAttribute > ,
175+ parse_sess : & ' a ParseSess ,
176+ features : & ' a Features ,
243177}
244178
245179macro_rules! gate_feature_post {
246180 ( $cx: expr, $feature: ident, $span: expr, $explain: expr) => { {
247181 let ( cx, span) = ( $cx, $span) ;
248182 if !span. allows_unstable( sym:: $feature) {
249- gate_feature!( cx. context , $feature, span, $explain)
183+ gate_feature!( cx, $feature, span, $explain)
250184 }
251185 } } ;
252186 ( $cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { {
253187 let ( cx, span) = ( $cx, $span) ;
254188 if !span. allows_unstable( sym:: $feature) {
255- gate_feature!( cx. context , $feature, span, $explain, $level)
189+ gate_feature!( cx, $feature, span, $explain, $level)
256190 }
257191 } }
258192}
@@ -316,58 +250,52 @@ impl<'a> PostExpansionVisitor<'a> {
316250
317251impl < ' a > Visitor < ' a > for PostExpansionVisitor < ' a > {
318252 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 ) ;
350258 }
351-
259+ // Check input tokens for built-in and key-value attributes.
352260 match attr_info {
353261 // `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) ,
356264 _ => if let Some ( TokenTree :: Token ( token) ) = attr. tokens . trees ( ) . next ( ) {
357265 if token == token:: Eq {
358266 // 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 ( ) ;
360268 }
361269 }
362270 }
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+ }
363291 }
364292
365293 fn visit_name ( & mut self , sp : Span , name : ast:: Name ) {
366294 if !name. as_str ( ) . is_ascii ( ) {
367295 gate_feature_post ! (
368296 & self ,
369297 non_ascii_idents,
370- self . context . parse_sess. source_map( ) . def_span( sp) ,
298+ self . parse_sess. source_map( ) . def_span( sp) ,
371299 "non-ascii idents are not fully supported"
372300 ) ;
373301 }
@@ -423,12 +351,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
423351 }
424352 }
425353
426- let has_feature = self . context . features . arbitrary_enum_discriminant ;
354+ let has_feature = self . features . arbitrary_enum_discriminant ;
427355 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) ;
432357 }
433358 }
434359
@@ -538,7 +463,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
538463 ast:: ExprKind :: Type ( ..) => {
539464 // To avoid noise about type ascription in common syntax errors, only emit if it
540465 // 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 {
542467 gate_feature_post ! ( & self , type_ascription, e. span,
543468 "type ascription is experimental" ) ;
544469 }
@@ -872,22 +797,17 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item=&'static Featur
872797}
873798
874799pub fn check_crate ( krate : & ast:: Crate ,
875- sess : & ParseSess ,
800+ parse_sess : & ParseSess ,
876801 features : & Features ,
877- plugin_attributes : & [ ( Symbol , AttributeType ) ] ,
878802 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 } ;
885805
886806 macro_rules! gate_all {
887807 ( $gate: ident, $msg: literal) => { gate_all!( $gate, $gate, $msg) ; } ;
888808 ( $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) ;
891811 }
892812 }
893813 }
@@ -898,11 +818,7 @@ pub fn check_crate(krate: &ast::Crate,
898818 gate_all ! ( yields, generators, "yield syntax is experimental" ) ;
899819 gate_all ! ( or_patterns, "or-patterns syntax is experimental" ) ;
900820
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) ;
906822}
907823
908824#[ derive( Clone , Copy , Hash ) ]
0 commit comments