Skip to content

Commit dd96eff

Browse files
committed
Sort pre-expansion gates and add more visible disclaimers
1 parent 98688ef commit dd96eff

2 files changed

Lines changed: 97 additions & 68 deletions

File tree

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 87 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6271
impl<'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+
451462
pub 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
}

tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ error[E0405]: cannot find trait `r#use` in this scope
4646
LL | fn binder() -> impl Sized + for<'a> use<> {}
4747
| ^^^ not found in this scope
4848

49+
error[E0658]: const trait impls are experimental
50+
--> $DIR/bound-modifiers.rs:12:32
51+
|
52+
LL | fn constness() -> impl Sized + const use<> {}
53+
| ^^^^^
54+
|
55+
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
56+
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
57+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
58+
4959
error[E0658]: `async` trait bounds are unstable
5060
--> $DIR/bound-modifiers.rs:7:32
5161
|
@@ -57,16 +67,6 @@ LL | fn asyncness() -> impl Sized + async use<> {}
5767
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
5868
= help: use the desugared name of the async trait, such as `AsyncFn`
5969

60-
error[E0658]: const trait impls are experimental
61-
--> $DIR/bound-modifiers.rs:12:32
62-
|
63-
LL | fn constness() -> impl Sized + const use<> {}
64-
| ^^^^^
65-
|
66-
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
67-
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
68-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
69-
7070
error: aborting due to 10 previous errors
7171

7272
Some errors have detailed explanations: E0405, E0658.

0 commit comments

Comments
 (0)