@@ -13,34 +13,38 @@ use thin_vec::ThinVec;
1313
1414use crate :: errors;
1515
16- macro_rules! gate_feature_fn {
17- ( $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => { {
18- if !$has_feature( $visitor. features) && !$span. allows_unstable( $name) {
19- feature_err( & $visitor. sess. parse_sess, $name, $span, $explain) . help( $help) . emit( ) ;
16+ /// The common case.
17+ macro_rules! gate {
18+ ( $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { {
19+ if !$visitor. features. $feature && !$span. allows_unstable( sym:: $feature) {
20+ feature_err( & $visitor. sess. parse_sess, sym:: $feature, $span, $explain) . emit( ) ;
2021 }
2122 } } ;
22- ( $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => { {
23- if !$has_feature( $visitor. features) && !$span. allows_unstable( $name) {
24- feature_err( & $visitor. sess. parse_sess, $name, $span, $explain) . emit( ) ;
23+ ( $visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => { {
24+ if !$visitor. features. $feature && !$span. allows_unstable( sym:: $feature) {
25+ feature_err( & $visitor. sess. parse_sess, sym:: $feature, $span, $explain)
26+ . help( $help)
27+ . emit( ) ;
2528 }
2629 } } ;
27- ( future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => { {
28- if !$has_feature( $visitor. features) && !$span. allows_unstable( $name) {
29- feature_warn( & $visitor. sess. parse_sess, $name, $span, $explain) ;
30+ }
31+
32+ /// The unusual case, where the `has_feature` condition is non-standard.
33+ macro_rules! gate_alt {
34+ ( $visitor: expr, $has_feature: expr, $name: expr, $span: expr, $explain: expr) => { {
35+ if !$has_feature && !$span. allows_unstable( $name) {
36+ feature_err( & $visitor. sess. parse_sess, $name, $span, $explain) . emit( ) ;
3037 }
3138 } } ;
3239}
3340
34- macro_rules! gate_feature_post {
35- ( $visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => {
36- gate_feature_fn!( $visitor, |x: & Features | x. $feature, $span, sym:: $feature, $explain, $help)
37- } ;
38- ( $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
39- gate_feature_fn!( $visitor, |x: & Features | x. $feature, $span, sym:: $feature, $explain)
40- } ;
41- ( future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
42- gate_feature_fn!( future_incompatible; $visitor, |x: & Features | x. $feature, $span, sym:: $feature, $explain)
43- } ;
41+ /// The legacy case.
42+ macro_rules! gate_legacy {
43+ ( $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { {
44+ if !$visitor. features. $feature && !$span. allows_unstable( sym:: $feature) {
45+ feature_warn( & $visitor. sess. parse_sess, sym:: $feature, $span, $explain) ;
46+ }
47+ } } ;
4448}
4549
4650pub fn check_attribute ( attr : & ast:: Attribute , sess : & Session , features : & Features ) {
@@ -62,7 +66,7 @@ impl<'a> PostExpansionVisitor<'a> {
6266 match symbol_unescaped {
6367 // Stable
6468 sym:: Rust | sym:: C => { }
65- abi => gate_feature_post ! (
69+ abi => gate ! (
6670 & self ,
6771 const_extern_fn,
6872 span,
@@ -113,14 +117,14 @@ impl<'a> PostExpansionVisitor<'a> {
113117 fn visit_ty ( & mut self , ty : & ast:: Ty ) {
114118 if let ast:: TyKind :: ImplTrait ( ..) = ty. kind {
115119 if self . in_associated_ty {
116- gate_feature_post ! (
120+ gate ! (
117121 & self . vis,
118122 impl_trait_in_assoc_type,
119123 ty. span,
120124 "`impl Trait` in associated types is unstable"
121125 ) ;
122126 } else {
123- gate_feature_post ! (
127+ gate ! (
124128 & self . vis,
125129 type_alias_impl_trait,
126130 ty. span,
@@ -172,15 +176,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
172176 ..
173177 } ) = attr_info
174178 {
175- gate_feature_fn ! ( self , has_feature, attr . span , * name, * descr) ;
179+ gate_alt ! ( self , has_feature( & self . features ) , * name, attr . span , * descr) ;
176180 }
177181 // Check unstable flavors of the `#[doc]` attribute.
178182 if attr. has_name ( sym:: doc) {
179183 for nested_meta in attr. meta_item_list ( ) . unwrap_or_default ( ) {
180184 macro_rules! gate_doc { ( $( $s: literal { $( $name: ident => $feature: ident) * } ) * ) => {
181185 $( $( if nested_meta. has_name( sym:: $name) {
182186 let msg = concat!( "`#[doc(" , stringify!( $name) , ")]` is " , $s) ;
183- gate_feature_post !( self , $feature, attr. span, msg) ;
187+ gate !( self , $feature, attr. span, msg) ;
184188 } ) * ) *
185189 } }
186190
@@ -204,7 +208,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
204208 && !self . features . diagnostic_namespace
205209 {
206210 let msg = "`#[diagnostic]` attribute name space is experimental" ;
207- gate_feature_post ! ( self , diagnostic_namespace, seg. ident. span, msg) ;
211+ gate ! ( self , diagnostic_namespace, seg. ident. span, msg) ;
208212 }
209213
210214 // Emit errors for non-staged-api crates.
@@ -230,12 +234,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
230234
231235 ast:: ItemKind :: Fn ( ..) => {
232236 if attr:: contains_name ( & i. attrs , sym:: start) {
233- gate_feature_post ! (
237+ gate ! (
234238 & self ,
235239 start,
236240 i. span,
237- "`#[start]` functions are experimental \
238- and their signature may change \
241+ "`#[start]` functions are experimental and their signature may change \
239242 over time"
240243 ) ;
241244 }
@@ -245,7 +248,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
245248 for attr in attr:: filter_by_name ( & i. attrs , sym:: repr) {
246249 for item in attr. meta_item_list ( ) . unwrap_or_else ( ThinVec :: new) {
247250 if item. has_name ( sym:: simd) {
248- gate_feature_post ! (
251+ gate ! (
249252 & self ,
250253 repr_simd,
251254 attr. span,
@@ -258,7 +261,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
258261
259262 ast:: ItemKind :: Impl ( box ast:: Impl { polarity, defaultness, of_trait, .. } ) => {
260263 if let & ast:: ImplPolarity :: Negative ( span) = polarity {
261- gate_feature_post ! (
264+ gate ! (
262265 & self ,
263266 negative_impls,
264267 span. to( of_trait. as_ref( ) . map_or( span, |t| t. path. span) ) ,
@@ -268,12 +271,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
268271 }
269272
270273 if let ast:: Defaultness :: Default ( _) = defaultness {
271- gate_feature_post ! ( & self , specialization, i. span, "specialization is unstable" ) ;
274+ gate ! ( & self , specialization, i. span, "specialization is unstable" ) ;
272275 }
273276 }
274277
275278 ast:: ItemKind :: Trait ( box ast:: Trait { is_auto : ast:: IsAuto :: Yes , .. } ) => {
276- gate_feature_post ! (
279+ gate ! (
277280 & self ,
278281 auto_traits,
279282 i. span,
@@ -282,12 +285,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
282285 }
283286
284287 ast:: ItemKind :: TraitAlias ( ..) => {
285- gate_feature_post ! ( & self , trait_alias, i. span, "trait aliases are experimental" ) ;
288+ gate ! ( & self , trait_alias, i. span, "trait aliases are experimental" ) ;
286289 }
287290
288291 ast:: ItemKind :: MacroDef ( ast:: MacroDef { macro_rules : false , .. } ) => {
289292 let msg = "`macro` is experimental" ;
290- gate_feature_post ! ( & self , decl_macro, i. span, msg) ;
293+ gate ! ( & self , decl_macro, i. span, msg) ;
291294 }
292295
293296 ast:: ItemKind :: TyAlias ( box ast:: TyAlias { ty : Some ( ty) , .. } ) => {
@@ -306,7 +309,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
306309 let link_name = attr:: first_attr_value_str_by_name ( & i. attrs , sym:: link_name) ;
307310 let links_to_llvm = link_name. is_some_and ( |val| val. as_str ( ) . starts_with ( "llvm." ) ) ;
308311 if links_to_llvm {
309- gate_feature_post ! (
312+ gate ! (
310313 & self ,
311314 link_llvm_intrinsics,
312315 i. span,
@@ -315,7 +318,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
315318 }
316319 }
317320 ast:: ForeignItemKind :: TyAlias ( ..) => {
318- gate_feature_post ! ( & self , extern_types, i. span, "extern types are experimental" ) ;
321+ gate ! ( & self , extern_types, i. span, "extern types are experimental" ) ;
319322 }
320323 ast:: ForeignItemKind :: MacCall ( ..) => { }
321324 }
@@ -331,7 +334,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
331334 self . check_late_bound_lifetime_defs ( & bare_fn_ty. generic_params ) ;
332335 }
333336 ast:: TyKind :: Never => {
334- gate_feature_post ! ( & self , never_type, ty. span, "the `!` type is experimental" ) ;
337+ gate ! ( & self , never_type, ty. span, "the `!` type is experimental" ) ;
335338 }
336339 _ => { }
337340 }
@@ -364,7 +367,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
364367 fn visit_expr ( & mut self , e : & ' a ast:: Expr ) {
365368 match e. kind {
366369 ast:: ExprKind :: TryBlock ( _) => {
367- gate_feature_post ! ( & self , try_blocks, e. span, "`try` expression is experimental" ) ;
370+ gate ! ( & self , try_blocks, e. span, "`try` expression is experimental" ) ;
368371 }
369372 _ => { }
370373 }
@@ -380,7 +383,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
380383 _ => pat,
381384 } ;
382385 if let PatKind :: Range ( Some ( _) , None , Spanned { .. } ) = inner_pat. kind {
383- gate_feature_post ! (
386+ gate ! (
384387 & self ,
385388 half_open_range_patterns_in_slices,
386389 pat. span,
@@ -390,15 +393,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
390393 }
391394 }
392395 PatKind :: Box ( ..) => {
393- gate_feature_post ! (
394- & self ,
395- box_patterns,
396- pattern. span,
397- "box pattern syntax is experimental"
398- ) ;
396+ gate ! ( & self , box_patterns, pattern. span, "box pattern syntax is experimental" ) ;
399397 }
400398 PatKind :: Range ( _, Some ( _) , Spanned { node : RangeEnd :: Excluded , .. } ) => {
401- gate_feature_post ! (
399+ gate ! (
402400 & self ,
403401 exclusive_range_pattern,
404402 pattern. span,
@@ -426,7 +424,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
426424 }
427425
428426 if fn_kind. ctxt ( ) != Some ( FnCtxt :: Foreign ) && fn_kind. decl ( ) . c_variadic ( ) {
429- gate_feature_post ! ( & self , c_variadic, span, "C-variadic functions are unstable" ) ;
427+ gate ! ( & self , c_variadic, span, "C-variadic functions are unstable" ) ;
430428 }
431429
432430 visit:: walk_fn ( self , fn_kind)
@@ -438,14 +436,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
438436 && args. inputs . is_empty ( )
439437 && matches ! ( args. output, ast:: FnRetTy :: Default ( ..) )
440438 {
441- gate_feature_post ! (
439+ gate ! (
442440 & self ,
443441 return_type_notation,
444442 constraint. span,
445443 "return type notation is experimental"
446444 ) ;
447445 } else {
448- gate_feature_post ! (
446+ gate ! (
449447 & self ,
450448 associated_type_bounds,
451449 constraint. span,
@@ -461,7 +459,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
461459 ast:: AssocItemKind :: Fn ( _) => true ,
462460 ast:: AssocItemKind :: Type ( box ast:: TyAlias { ty, .. } ) => {
463461 if let ( Some ( _) , AssocCtxt :: Trait ) = ( ty, ctxt) {
464- gate_feature_post ! (
462+ gate ! (
465463 & self ,
466464 associated_type_defaults,
467465 i. span,
@@ -477,11 +475,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
477475 } ;
478476 if let ast:: Defaultness :: Default ( _) = i. kind . defaultness ( ) {
479477 // Limit `min_specialization` to only specializing functions.
480- gate_feature_fn ! (
478+ gate_alt ! (
481479 & self ,
482- |x: & Features | x. specialization || ( is_fn && x. min_specialization) ,
483- i. span,
480+ self . features. specialization || ( is_fn && self . features. min_specialization) ,
484481 sym:: specialization,
482+ i. span,
485483 "specialization is unstable"
486484 ) ;
487485 }
@@ -496,17 +494,17 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
496494
497495 let spans = sess. parse_sess . gated_spans . spans . borrow ( ) ;
498496 macro_rules! gate_all {
499- ( $gate: ident, $msg: literal, $help : literal ) => {
497+ ( $gate: ident, $msg: literal) => {
500498 if let Some ( spans) = spans. get( & sym:: $gate) {
501499 for span in spans {
502- gate_feature_post !( & visitor, $gate, * span, $msg, $help ) ;
500+ gate !( & visitor, $gate, * span, $msg) ;
503501 }
504502 }
505503 } ;
506- ( $gate: ident, $msg: literal) => {
504+ ( $gate: ident, $msg: literal, $help : literal ) => {
507505 if let Some ( spans) = spans. get( & sym:: $gate) {
508506 for span in spans {
509- gate_feature_post !( & visitor, $gate, * span, $msg) ;
507+ gate !( & visitor, $gate, * span, $msg, $help ) ;
510508 }
511509 }
512510 } ;
@@ -531,7 +529,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
531529 gate_all ! ( more_qualified_paths, "usage of qualified paths in this context is experimental" ) ;
532530 for & span in spans. get ( & sym:: yield_expr) . iter ( ) . copied ( ) . flatten ( ) {
533531 if !span. at_least_rust_2024 ( ) {
534- gate_feature_post ! ( & visitor, coroutines, span, "yield syntax is experimental" ) ;
532+ gate ! ( & visitor, coroutines, span, "yield syntax is experimental" ) ;
535533 }
536534 }
537535 gate_all ! ( gen_blocks, "gen blocks are experimental" ) ;
@@ -565,7 +563,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565563 macro_rules! gate_all_legacy_dont_use {
566564 ( $gate: ident, $msg: literal) => {
567565 for span in spans. get( & sym:: $gate) . unwrap_or( & vec![ ] ) {
568- gate_feature_post! ( future_incompatible ; & visitor, $gate, * span, $msg) ;
566+ gate_legacy! ( & visitor, $gate, * span, $msg) ;
569567 }
570568 } ;
571569 }
0 commit comments