@@ -13,34 +13,38 @@ use thin_vec::ThinVec;
13
13
14
14
use crate :: errors;
15
15
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( ) ;
20
21
}
21
22
} } ;
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( ) ;
25
28
}
26
29
} } ;
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( ) ;
30
37
}
31
38
} } ;
32
39
}
33
40
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
+ } } ;
44
48
}
45
49
46
50
pub fn check_attribute ( attr : & ast:: Attribute , sess : & Session , features : & Features ) {
@@ -62,7 +66,7 @@ impl<'a> PostExpansionVisitor<'a> {
62
66
match symbol_unescaped {
63
67
// Stable
64
68
sym:: Rust | sym:: C => { }
65
- abi => gate_feature_post ! (
69
+ abi => gate ! (
66
70
& self ,
67
71
const_extern_fn,
68
72
span,
@@ -113,14 +117,14 @@ impl<'a> PostExpansionVisitor<'a> {
113
117
fn visit_ty ( & mut self , ty : & ast:: Ty ) {
114
118
if let ast:: TyKind :: ImplTrait ( ..) = ty. kind {
115
119
if self . in_associated_ty {
116
- gate_feature_post ! (
120
+ gate ! (
117
121
& self . vis,
118
122
impl_trait_in_assoc_type,
119
123
ty. span,
120
124
"`impl Trait` in associated types is unstable"
121
125
) ;
122
126
} else {
123
- gate_feature_post ! (
127
+ gate ! (
124
128
& self . vis,
125
129
type_alias_impl_trait,
126
130
ty. span,
@@ -172,15 +176,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
172
176
..
173
177
} ) = attr_info
174
178
{
175
- gate_feature_fn ! ( self , has_feature, attr . span , * name, * descr) ;
179
+ gate_alt ! ( self , has_feature( & self . features ) , * name, attr . span , * descr) ;
176
180
}
177
181
// Check unstable flavors of the `#[doc]` attribute.
178
182
if attr. has_name ( sym:: doc) {
179
183
for nested_meta in attr. meta_item_list ( ) . unwrap_or_default ( ) {
180
184
macro_rules! gate_doc { ( $( $s: literal { $( $name: ident => $feature: ident) * } ) * ) => {
181
185
$( $( if nested_meta. has_name( sym:: $name) {
182
186
let msg = concat!( "`#[doc(" , stringify!( $name) , ")]` is " , $s) ;
183
- gate_feature_post !( self , $feature, attr. span, msg) ;
187
+ gate !( self , $feature, attr. span, msg) ;
184
188
} ) * ) *
185
189
} }
186
190
@@ -204,7 +208,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
204
208
&& !self . features . diagnostic_namespace
205
209
{
206
210
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) ;
208
212
}
209
213
210
214
// Emit errors for non-staged-api crates.
@@ -230,12 +234,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
230
234
231
235
ast:: ItemKind :: Fn ( ..) => {
232
236
if attr:: contains_name ( & i. attrs , sym:: start) {
233
- gate_feature_post ! (
237
+ gate ! (
234
238
& self ,
235
239
start,
236
240
i. span,
237
- "`#[start]` functions are experimental \
238
- and their signature may change \
241
+ "`#[start]` functions are experimental and their signature may change \
239
242
over time"
240
243
) ;
241
244
}
@@ -245,7 +248,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
245
248
for attr in attr:: filter_by_name ( & i. attrs , sym:: repr) {
246
249
for item in attr. meta_item_list ( ) . unwrap_or_else ( ThinVec :: new) {
247
250
if item. has_name ( sym:: simd) {
248
- gate_feature_post ! (
251
+ gate ! (
249
252
& self ,
250
253
repr_simd,
251
254
attr. span,
@@ -258,7 +261,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
258
261
259
262
ast:: ItemKind :: Impl ( box ast:: Impl { polarity, defaultness, of_trait, .. } ) => {
260
263
if let & ast:: ImplPolarity :: Negative ( span) = polarity {
261
- gate_feature_post ! (
264
+ gate ! (
262
265
& self ,
263
266
negative_impls,
264
267
span. to( of_trait. as_ref( ) . map_or( span, |t| t. path. span) ) ,
@@ -268,12 +271,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
268
271
}
269
272
270
273
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" ) ;
272
275
}
273
276
}
274
277
275
278
ast:: ItemKind :: Trait ( box ast:: Trait { is_auto : ast:: IsAuto :: Yes , .. } ) => {
276
- gate_feature_post ! (
279
+ gate ! (
277
280
& self ,
278
281
auto_traits,
279
282
i. span,
@@ -282,12 +285,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
282
285
}
283
286
284
287
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" ) ;
286
289
}
287
290
288
291
ast:: ItemKind :: MacroDef ( ast:: MacroDef { macro_rules : false , .. } ) => {
289
292
let msg = "`macro` is experimental" ;
290
- gate_feature_post ! ( & self , decl_macro, i. span, msg) ;
293
+ gate ! ( & self , decl_macro, i. span, msg) ;
291
294
}
292
295
293
296
ast:: ItemKind :: TyAlias ( box ast:: TyAlias { ty : Some ( ty) , .. } ) => {
@@ -306,7 +309,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
306
309
let link_name = attr:: first_attr_value_str_by_name ( & i. attrs , sym:: link_name) ;
307
310
let links_to_llvm = link_name. is_some_and ( |val| val. as_str ( ) . starts_with ( "llvm." ) ) ;
308
311
if links_to_llvm {
309
- gate_feature_post ! (
312
+ gate ! (
310
313
& self ,
311
314
link_llvm_intrinsics,
312
315
i. span,
@@ -315,7 +318,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
315
318
}
316
319
}
317
320
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" ) ;
319
322
}
320
323
ast:: ForeignItemKind :: MacCall ( ..) => { }
321
324
}
@@ -331,7 +334,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
331
334
self . check_late_bound_lifetime_defs ( & bare_fn_ty. generic_params ) ;
332
335
}
333
336
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" ) ;
335
338
}
336
339
_ => { }
337
340
}
@@ -364,7 +367,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
364
367
fn visit_expr ( & mut self , e : & ' a ast:: Expr ) {
365
368
match e. kind {
366
369
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" ) ;
368
371
}
369
372
_ => { }
370
373
}
@@ -380,7 +383,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
380
383
_ => pat,
381
384
} ;
382
385
if let PatKind :: Range ( Some ( _) , None , Spanned { .. } ) = inner_pat. kind {
383
- gate_feature_post ! (
386
+ gate ! (
384
387
& self ,
385
388
half_open_range_patterns_in_slices,
386
389
pat. span,
@@ -390,15 +393,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
390
393
}
391
394
}
392
395
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" ) ;
399
397
}
400
398
PatKind :: Range ( _, Some ( _) , Spanned { node : RangeEnd :: Excluded , .. } ) => {
401
- gate_feature_post ! (
399
+ gate ! (
402
400
& self ,
403
401
exclusive_range_pattern,
404
402
pattern. span,
@@ -426,7 +424,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
426
424
}
427
425
428
426
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" ) ;
430
428
}
431
429
432
430
visit:: walk_fn ( self , fn_kind)
@@ -438,14 +436,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
438
436
&& args. inputs . is_empty ( )
439
437
&& matches ! ( args. output, ast:: FnRetTy :: Default ( ..) )
440
438
{
441
- gate_feature_post ! (
439
+ gate ! (
442
440
& self ,
443
441
return_type_notation,
444
442
constraint. span,
445
443
"return type notation is experimental"
446
444
) ;
447
445
} else {
448
- gate_feature_post ! (
446
+ gate ! (
449
447
& self ,
450
448
associated_type_bounds,
451
449
constraint. span,
@@ -461,7 +459,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
461
459
ast:: AssocItemKind :: Fn ( _) => true ,
462
460
ast:: AssocItemKind :: Type ( box ast:: TyAlias { ty, .. } ) => {
463
461
if let ( Some ( _) , AssocCtxt :: Trait ) = ( ty, ctxt) {
464
- gate_feature_post ! (
462
+ gate ! (
465
463
& self ,
466
464
associated_type_defaults,
467
465
i. span,
@@ -477,11 +475,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
477
475
} ;
478
476
if let ast:: Defaultness :: Default ( _) = i. kind . defaultness ( ) {
479
477
// Limit `min_specialization` to only specializing functions.
480
- gate_feature_fn ! (
478
+ gate_alt ! (
481
479
& self ,
482
- |x: & Features | x. specialization || ( is_fn && x. min_specialization) ,
483
- i. span,
480
+ self . features. specialization || ( is_fn && self . features. min_specialization) ,
484
481
sym:: specialization,
482
+ i. span,
485
483
"specialization is unstable"
486
484
) ;
487
485
}
@@ -496,17 +494,17 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
496
494
497
495
let spans = sess. parse_sess . gated_spans . spans . borrow ( ) ;
498
496
macro_rules! gate_all {
499
- ( $gate: ident, $msg: literal, $help : literal ) => {
497
+ ( $gate: ident, $msg: literal) => {
500
498
if let Some ( spans) = spans. get( & sym:: $gate) {
501
499
for span in spans {
502
- gate_feature_post !( & visitor, $gate, * span, $msg, $help ) ;
500
+ gate !( & visitor, $gate, * span, $msg) ;
503
501
}
504
502
}
505
503
} ;
506
- ( $gate: ident, $msg: literal) => {
504
+ ( $gate: ident, $msg: literal, $help : literal ) => {
507
505
if let Some ( spans) = spans. get( & sym:: $gate) {
508
506
for span in spans {
509
- gate_feature_post !( & visitor, $gate, * span, $msg) ;
507
+ gate !( & visitor, $gate, * span, $msg, $help ) ;
510
508
}
511
509
}
512
510
} ;
@@ -531,7 +529,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
531
529
gate_all ! ( more_qualified_paths, "usage of qualified paths in this context is experimental" ) ;
532
530
for & span in spans. get ( & sym:: yield_expr) . iter ( ) . copied ( ) . flatten ( ) {
533
531
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" ) ;
535
533
}
536
534
}
537
535
gate_all ! ( gen_blocks, "gen blocks are experimental" ) ;
@@ -565,7 +563,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565
563
macro_rules! gate_all_legacy_dont_use {
566
564
( $gate: ident, $msg: literal) => {
567
565
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) ;
569
567
}
570
568
} ;
571
569
}
0 commit comments