@@ -59,6 +59,15 @@ struct PostExpansionVisitor<'a> {
5959 features : & ' a Features ,
6060}
6161
62+ // -----------------------------------------------------------------------------
63+ // POST-EXPANSION FEATURE GATES FOR UNSTABLE ATTRIBUTES ETC.
64+ // **LEGACY** POST-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX **LEGACY**
65+ // -----------------------------------------------------------------------------
66+
67+ // IMPORTANT: Don't add any new post-expansion feature gates for new unstable syntax!
68+ // It's a legacy mechanism for them.
69+ // Instead, register a pre-expansion feature gate using `gate_all` in fn `check_crate`.
70+
6271impl < ' a > PostExpansionVisitor < ' a > {
6372 /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
6473 fn check_impl_trait ( & self , ty : & ast:: Ty , in_associated_ty : bool ) {
@@ -448,6 +457,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
448457 }
449458}
450459
460+ // -----------------------------------------------------------------------------
461+
451462pub fn check_crate ( krate : & ast:: Crate , sess : & Session , features : & Features ) {
452463 maybe_stage_features ( sess, features, krate) ;
453464 check_incompatible_features ( sess, features) ;
@@ -456,6 +467,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
456467
457468 let mut visitor = PostExpansionVisitor { sess, features } ;
458469
470+ // -----------------------------------------------------------------------------
471+ // PRE-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX
472+ // -----------------------------------------------------------------------------
473+
459474 let spans = sess. psess . gated_spans . spans . borrow ( ) ;
460475 macro_rules! gate_all {
461476 ( $feature: ident, $explain: literal $( , $help: literal) ?) => {
@@ -464,54 +479,63 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
464479 }
465480 } ;
466481 }
482+
483+ // tidy-alphabetical-start
484+ gate_all ! ( async_for_loop, "`for await` loops are experimental" ) ;
485+ gate_all ! ( builtin_syntax, "`builtin #` syntax is unstable" ) ;
486+ gate_all ! ( const_block_items, "const block items are experimental" ) ;
487+ gate_all ! ( const_closures, "const closures are experimental" ) ;
488+ gate_all ! ( const_trait_impl, "const trait impls are experimental" ) ;
489+ gate_all ! ( contracts, "contracts are incomplete" ) ;
490+ gate_all ! ( contracts_internals, "contract internal machinery is for internal use only" ) ;
491+ gate_all ! ( coroutines, "coroutine syntax is experimental" ) ;
492+ gate_all ! ( default_field_values, "default values on fields are experimental" ) ;
493+ gate_all ! ( ergonomic_clones, "ergonomic clones are experimental" ) ;
494+ gate_all ! ( explicit_tail_calls, "`become` expression is experimental" ) ;
495+ gate_all ! ( final_associated_functions, "`final` on trait functions is experimental" ) ;
496+ gate_all ! ( fn_delegation, "functions delegation is not yet fully implemented" ) ;
497+ gate_all ! ( frontmatter, "frontmatters are experimental" ) ;
498+ gate_all ! ( gen_blocks, "gen blocks are experimental" ) ;
499+ gate_all ! ( generic_const_items, "generic const items are experimental" ) ;
500+ gate_all ! ( global_registration, "global registration is experimental" ) ;
501+ gate_all ! ( guard_patterns, "guard patterns are experimental" , "consider using match arm guards" ) ;
502+ gate_all ! ( impl_restriction, "`impl` restrictions are experimental" ) ;
503+ gate_all ! ( min_generic_const_args, "unbraced const blocks as const args are experimental" ) ;
504+ gate_all ! ( more_qualified_paths, "usage of qualified paths in this context is experimental" ) ;
505+ gate_all ! ( mut_ref, "mutable by-reference bindings are experimental" ) ;
506+ gate_all ! ( pin_ergonomics, "pinned reference syntax is experimental" ) ;
507+ gate_all ! ( postfix_match, "postfix match is experimental" ) ;
508+ gate_all ! ( return_type_notation, "return type notation is experimental" ) ;
509+ gate_all ! ( super_let, "`super let` is experimental" ) ;
510+ gate_all ! ( try_blocks_heterogeneous, "`try bikeshed` expression is experimental" ) ;
511+ gate_all ! ( unsafe_binders, "unsafe binder types are experimental" ) ;
512+ gate_all ! ( unsafe_fields, "`unsafe` fields are experimental" ) ;
513+ gate_all ! ( where_clause_attrs, "attributes in `where` clause are unstable" ) ;
514+ gate_all ! ( yeet_expr, "`do yeet` expression is experimental" ) ;
515+ // tidy-alphabetical-end
516+
467517 gate_all ! (
468518 async_trait_bounds,
469519 "`async` trait bounds are unstable" ,
470520 "use the desugared name of the async trait, such as `AsyncFn`"
471521 ) ;
472- gate_all ! ( async_for_loop, "`for await` loops are experimental" ) ;
473522 gate_all ! (
474523 closure_lifetime_binder,
475524 "`for<...>` binders for closures are experimental" ,
476525 "consider removing `for<...>`"
477526 ) ;
478- gate_all ! ( more_qualified_paths, "usage of qualified paths in this context is experimental" ) ;
479- // Yield exprs can be enabled either by `yield_expr`, by `coroutines` or by `gen_blocks`.
480- for & span in spans. get ( & sym:: yield_expr) . into_iter ( ) . flatten ( ) {
481- if ( !visitor. features . coroutines ( ) && !span. allows_unstable ( sym:: coroutines) )
482- && ( !visitor. features . gen_blocks ( ) && !span. allows_unstable ( sym:: gen_blocks) )
483- && ( !visitor. features . yield_expr ( ) && !span. allows_unstable ( sym:: yield_expr) )
484- {
485- // Emit yield_expr as the error, since that will be sufficient. You can think of it
486- // as coroutines and gen_blocks imply yield_expr.
487- feature_err ( visitor. sess , sym:: yield_expr, span, "yield syntax is experimental" ) . emit ( ) ;
488- }
489- }
490- gate_all ! ( gen_blocks, "gen blocks are experimental" ) ;
491- gate_all ! ( const_trait_impl, "const trait impls are experimental" ) ;
492527 gate_all ! (
493528 half_open_range_patterns_in_slices,
494529 "half-open range patterns in slices are unstable"
495530 ) ;
496- gate_all ! ( try_blocks_heterogeneous, "`try bikeshed` expression is experimental" ) ;
497- gate_all ! ( yeet_expr, "`do yeet` expression is experimental" ) ;
498- gate_all ! ( const_closures, "const closures are experimental" ) ;
499- gate_all ! ( builtin_syntax, "`builtin #` syntax is unstable" ) ;
500- gate_all ! ( ergonomic_clones, "ergonomic clones are experimental" ) ;
501- gate_all ! ( explicit_tail_calls, "`become` expression is experimental" ) ;
502- gate_all ! ( generic_const_items, "generic const items are experimental" ) ;
503- gate_all ! ( guard_patterns, "guard patterns are experimental" , "consider using match arm guards" ) ;
504- gate_all ! ( default_field_values, "default values on fields are experimental" ) ;
505- gate_all ! ( fn_delegation, "functions delegation is not yet fully implemented" ) ;
506- gate_all ! ( postfix_match, "postfix match is experimental" ) ;
507- gate_all ! ( mut_ref, "mutable by-reference bindings are experimental" ) ;
508- gate_all ! ( min_generic_const_args, "unbraced const blocks as const args are experimental" ) ;
509- // `associated_const_equality` will be stabilized as part of `min_generic_const_args`.
531+
532+ // `associated_const_equality` will be stabilized as part of `min_generic_const_args`.
510533 for & span in spans. get ( & sym:: associated_const_equality) . into_iter ( ) . flatten ( ) {
511534 gate ! ( visitor, min_generic_const_args, span, "associated const equality is incomplete" ) ;
512535 }
513- // `mgca_type_const_syntax` is part of `min_generic_const_args` so either
514- // or both are enabled we don't need to emit a feature error.
536+
537+ // `mgca_type_const_syntax` is part of `min_generic_const_args` so if
538+ // either or both are enabled we don't need to emit a feature error.
515539 for & span in spans. get ( & sym:: mgca_type_const_syntax) . into_iter ( ) . flatten ( ) {
516540 if visitor. features . min_generic_const_args ( )
517541 || visitor. features . mgca_type_const_syntax ( )
@@ -529,33 +553,23 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
529553 . emit ( ) ;
530554 }
531555
532- gate_all ! ( global_registration, "global registration is experimental" ) ;
533- gate_all ! ( return_type_notation, "return type notation is experimental" ) ;
534- gate_all ! ( pin_ergonomics, "pinned reference syntax is experimental" ) ;
535- gate_all ! ( unsafe_fields, "`unsafe` fields are experimental" ) ;
536- gate_all ! ( unsafe_binders, "unsafe binder types are experimental" ) ;
537- gate_all ! ( contracts, "contracts are incomplete" ) ;
538- gate_all ! ( contracts_internals, "contract internal machinery is for internal use only" ) ;
539- gate_all ! ( where_clause_attrs, "attributes in `where` clause are unstable" ) ;
540- gate_all ! ( super_let, "`super let` is experimental" ) ;
541- gate_all ! ( frontmatter, "frontmatters are experimental" ) ;
542- gate_all ! ( coroutines, "coroutine syntax is experimental" ) ;
543- gate_all ! ( const_block_items, "const block items are experimental" ) ;
544- gate_all ! ( final_associated_functions, "`final` on trait functions is experimental" ) ;
545- gate_all ! ( impl_restriction, "`impl` restrictions are experimental" ) ;
556+ // Negative bounds are *super* internal.
557+ // Under no circumstances do we want to advertise the feature name to users!
558+ if !visitor. features . negative_bounds ( ) {
559+ for & span in spans. get ( & sym:: negative_bounds) . into_iter ( ) . flatten ( ) {
560+ sess. dcx ( ) . emit_err ( errors:: NegativeBoundUnsupported { span } ) ;
561+ }
562+ }
546563
547564 if !visitor. features . never_patterns ( ) {
548565 for & span in spans. get ( & sym:: never_patterns) . into_iter ( ) . flatten ( ) {
549566 if span. allows_unstable ( sym:: never_patterns) {
550567 continue ;
551568 }
552- let sm = sess. source_map ( ) ;
553569 // We gate two types of spans: the span of a `!` pattern, and the span of a
554570 // match arm without a body. For the latter we want to give the user a normal
555571 // error.
556- if let Ok ( snippet) = sm. span_to_snippet ( span)
557- && snippet == "!"
558- {
572+ if let Ok ( "!" ) = sess. source_map ( ) . span_to_snippet ( span) . as_deref ( ) {
559573 feature_err ( sess, sym:: never_patterns, span, "`!` patterns are experimental" )
560574 . emit ( ) ;
561575 } else {
@@ -565,16 +579,27 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565579 }
566580 }
567581
568- if !visitor. features . negative_bounds ( ) {
569- for & span in spans. get ( & sym:: negative_bounds) . into_iter ( ) . flatten ( ) {
570- sess. dcx ( ) . emit_err ( errors:: NegativeBoundUnsupported { span } ) ;
582+ // Yield exprs can be enabled either by `yield_expr`, by `coroutines` or by `gen_blocks`.
583+ for & span in spans. get ( & sym:: yield_expr) . into_iter ( ) . flatten ( ) {
584+ if ( !visitor. features . coroutines ( ) && !span. allows_unstable ( sym:: coroutines) )
585+ && ( !visitor. features . gen_blocks ( ) && !span. allows_unstable ( sym:: gen_blocks) )
586+ && ( !visitor. features . yield_expr ( ) && !span. allows_unstable ( sym:: yield_expr) )
587+ {
588+ // Only mentioned `yield_expr` in the diagnostic since that'll be sufficient.
589+ // You can think of it as `coroutines` and `gen_blocks` implying `yield_expr`.
590+ feature_err ( visitor. sess , sym:: yield_expr, span, "yield syntax is experimental" ) . emit ( ) ;
571591 }
572592 }
573593
574- // All uses of `gate_all_legacy_dont_use!` below this point were added in #65742,
575- // and subsequently disabled (with the non-early gating readded).
576- // We emit an early future-incompatible warning for these.
577- // New syntax gates should go above here to get a hard error gate.
594+ // -----------------------------------------------------------------------------
595+ // **LEGACY** SOFT PRE-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX **LEGACY**
596+ // -----------------------------------------------------------------------------
597+
598+ // IMPORTANT: Do not extend the list below! New syntax should go above and use `gate_all`.
599+
600+ // FIXME(#154045): Migrate all of these to erroring feature gates and
601+ // remove the corresponding post-expansion feature gates.
602+
578603 macro_rules! soft_gate_all_legacy_dont_use {
579604 ( $feature: ident, $explain: literal) => {
580605 for & span in spans. get( & sym:: $feature) . into_iter( ) . flatten( ) {
@@ -585,11 +610,15 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
585610 } ;
586611 }
587612
613+ // tidy-alphabetical-start
614+ soft_gate_all_legacy_dont_use ! ( auto_traits, "`auto` traits are unstable" ) ;
588615 soft_gate_all_legacy_dont_use ! ( box_patterns, "box pattern syntax is experimental" ) ;
589- soft_gate_all_legacy_dont_use ! ( trait_alias, "trait aliases are experimental" ) ;
590616 soft_gate_all_legacy_dont_use ! ( decl_macro, "`macro` is experimental" ) ;
617+ soft_gate_all_legacy_dont_use ! ( trait_alias, "trait aliases are experimental" ) ;
591618 soft_gate_all_legacy_dont_use ! ( try_blocks, "`try` blocks are unstable" ) ;
592- soft_gate_all_legacy_dont_use ! ( auto_traits, "`auto` traits are unstable" ) ;
619+ // tidy-alphabetical-end
620+
621+ // -----------------------------------------------------------------------------
593622
594623 visit:: walk_crate ( & mut visitor, krate) ;
595624}
0 commit comments