Skip to main content

rustc_ast_passes/
feature_gate.rs

1use rustc_ast::visit::{self, AssocCtxt, FnKind, Visitor};
2use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token};
3use rustc_attr_ir::{Attribute, AttributeKind};
4use rustc_attr_parsing::AttributeParser;
5use rustc_errors::msg;
6use rustc_feature::{DependentFeature, Features};
7use rustc_session::Session;
8use rustc_session::config::NextSolverConfig;
9use rustc_session::diagnostics::{feature_err, feature_warn};
10use rustc_span::{Span, Spanned, sym};
11
12use crate::diagnostics;
13
14/// The common case.
15macro_rules! gate {
16    ($visitor:expr, $feature:ident, $span:expr, $explain:expr $(, $help:expr)?) => {{
17        if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
18            feature_err($visitor.sess, sym::$feature, $span, $explain)
19                $(.with_help($help))?
20                .emit();
21        }
22    }};
23}
24
25/// The unusual case, where the `has_feature` condition is non-standard.
26macro_rules! gate_alt {
27    ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr $(, $notes:expr)?) => {{
28        if !$has_feature && !$span.allows_unstable($name) {
29            #[allow(unused_mut)]
30            let mut diag = feature_err($visitor.sess, $name, $span, $explain);
31            $(for &note in $notes { diag.note(note); })?
32            diag.emit();
33        }
34    }};
35}
36
37/// The case involving a multispan.
38macro_rules! gate_multi {
39    ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
40        if !$visitor.features.$feature() {
41            let spans: Vec<_> =
42                $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
43            if !spans.is_empty() {
44                feature_err($visitor.sess, sym::$feature, spans, $explain).emit();
45            }
46        }
47    }};
48}
49
50struct PostExpansionVisitor<'a> {
51    sess: &'a Session,
52
53    // `sess` contains a `Features`, but this might not be that one.
54    features: &'a Features,
55}
56
57// -----------------------------------------------------------------------------
58// POST-EXPANSION FEATURE GATES FOR UNSTABLE ATTRIBUTES ETC.
59// **LEGACY**  POST-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX  **LEGACY**
60// -----------------------------------------------------------------------------
61
62// IMPORTANT: Don't add any new post-expansion feature gates for new unstable syntax!
63//            It's a legacy mechanism for them.
64//            Instead, register a pre-expansion feature gate using `gate_all` in fn `check_crate`.
65
66impl<'a> PostExpansionVisitor<'a> {
67    /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
68    fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) {
69        struct ImplTraitVisitor<'a> {
70            vis: &'a PostExpansionVisitor<'a>,
71            in_associated_ty: bool,
72        }
73        impl Visitor<'_> for ImplTraitVisitor<'_> {
74            fn visit_ty(&mut self, ty: &ast::Ty) {
75                if let ast::TyKind::ImplTrait(..) = ty.kind {
76                    if self.in_associated_ty {
77                        {
    if !self.vis.features.impl_trait_in_assoc_type() &&
            !ty.span.allows_unstable(sym::impl_trait_in_assoc_type) {
        feature_err(self.vis.sess, sym::impl_trait_in_assoc_type, ty.span,
                "`impl Trait` in associated types is unstable").emit();
    }
};gate!(
78                            self.vis,
79                            impl_trait_in_assoc_type,
80                            ty.span,
81                            "`impl Trait` in associated types is unstable"
82                        );
83                    } else {
84                        {
    if !self.vis.features.type_alias_impl_trait() &&
            !ty.span.allows_unstable(sym::type_alias_impl_trait) {
        feature_err(self.vis.sess, sym::type_alias_impl_trait, ty.span,
                "`impl Trait` in type aliases is unstable").emit();
    }
};gate!(
85                            self.vis,
86                            type_alias_impl_trait,
87                            ty.span,
88                            "`impl Trait` in type aliases is unstable"
89                        );
90                    }
91                }
92                visit::walk_ty(self, ty);
93            }
94
95            fn visit_anon_const(&mut self, _: &ast::AnonConst) -> Self::Result {
96                // We don't walk the anon const because it crosses a conceptual boundary: We're no
97                // longer "inside" the original type.
98                // Brittle: We assume that the callers of `check_impl_trait` will later recurse into
99                // the items found in the AnonConst to look for nested TyAliases.
100            }
101        }
102        ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty);
103    }
104
105    fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
106        // Check only lifetime parameters are present and that the
107        // generic parameters that are present have no bounds.
108        let non_lt_param_spans = params.iter().filter_map(|param| match param.kind {
109            ast::GenericParamKind::Lifetime { .. } => None,
110            _ => Some(param.ident.span),
111        });
112        {
    if !(&self).features.non_lifetime_binders() {
        let spans: Vec<_> =
            non_lt_param_spans.filter(|span|
                        !span.allows_unstable(sym::non_lifetime_binders)).collect();
        if !spans.is_empty() {
            feature_err((&self).sess, sym::non_lifetime_binders, spans,
                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("only lifetime parameters can be used in this context"))).emit();
        }
    }
};gate_multi!(
113            &self,
114            non_lifetime_binders,
115            non_lt_param_spans,
116            msg!("only lifetime parameters can be used in this context")
117        );
118
119        // FIXME(non_lifetime_binders): Const bound params are pretty broken.
120        // Let's keep users from using this feature accidentally.
121        if self.features.non_lifetime_binders() {
122            let const_param_spans: Vec<_> = params
123                .iter()
124                .filter_map(|param| match param.kind {
125                    ast::GenericParamKind::Const { .. } => Some(param.ident.span),
126                    _ => None,
127                })
128                .collect();
129
130            if !const_param_spans.is_empty() {
131                self.sess.dcx().emit_err(diagnostics::ForbiddenConstParam { const_param_spans });
132            }
133        }
134
135        for param in params {
136            if !param.bounds.is_empty() {
137                let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
138                if param.bounds.iter().any(|bound| #[allow(non_exhaustive_omitted_patterns)] match bound {
    GenericBound::Trait(_) => true,
    _ => false,
}matches!(bound, GenericBound::Trait(_))) {
139                    // Issue #149695
140                    // Abort immediately otherwise items defined in complex bounds will be lowered into HIR,
141                    // which will cause ICEs when errors of the items visit unlowered parents.
142                    self.sess.dcx().emit_fatal(diagnostics::ForbiddenBound { spans });
143                } else {
144                    self.sess.dcx().emit_err(diagnostics::ForbiddenBound { spans });
145                }
146            }
147        }
148    }
149}
150
151impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
152    fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
153        // Checked in attribute parsers, do NOT add checks here
154        visit::walk_attribute(self, attr)
155    }
156
157    fn visit_item(&mut self, i: &'a ast::Item) {
158        match &i.kind {
159            ast::ItemKind::ForeignMod(_foreign_module) => {
160                // handled during lowering
161            }
162            ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) => {
163                if let ast::ImplPolarity::Negative(span) = of_trait.polarity {
164                    {
    if !self.features.negative_impls() &&
            !span.to(of_trait.trait_ref.path.span).allows_unstable(sym::negative_impls)
        {
        feature_err(self.sess, sym::negative_impls,
                    span.to(of_trait.trait_ref.path.span),
                    "negative impls are experimental").with_help("use marker types for now").emit();
    }
};gate!(
165                        self,
166                        negative_impls,
167                        span.to(of_trait.trait_ref.path.span),
168                        "negative impls are experimental",
169                        "use marker types for now"
170                    );
171                }
172
173                if let ast::Defaultness::Default(_) = of_trait.defaultness {
174                    {
    if !self.features.specialization() &&
            !i.span.allows_unstable(sym::specialization) {
        feature_err(self.sess, sym::specialization, i.span,
                "specialization is experimental").emit();
    }
};gate!(self, specialization, i.span, "specialization is experimental");
175                }
176            }
177
178            ast::ItemKind::Trait(ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
179                {
    if !self.features.auto_traits() &&
            !i.span.allows_unstable(sym::auto_traits) {
        feature_err(self.sess, sym::auto_traits, i.span,
                "auto traits are experimental and possibly buggy").emit();
    }
};gate!(self, auto_traits, i.span, "auto traits are experimental and possibly buggy");
180            }
181
182            ast::ItemKind::TraitAlias(..) => {
183                {
    if !self.features.trait_alias() &&
            !i.span.allows_unstable(sym::trait_alias) {
        feature_err(self.sess, sym::trait_alias, i.span,
                "trait aliases are experimental").emit();
    }
};gate!(self, trait_alias, i.span, "trait aliases are experimental");
184            }
185
186            ast::ItemKind::MacroDef(_, ast::MacroDef { macro_rules: false, .. }) => {
187                let msg = "`macro` is experimental";
188                {
    if !self.features.decl_macro() && !i.span.allows_unstable(sym::decl_macro)
        {
        feature_err(self.sess, sym::decl_macro, i.span, msg).emit();
    }
};gate!(self, decl_macro, i.span, msg);
189            }
190
191            ast::ItemKind::TyAlias(ast::TyAlias { ty: Some(ty), .. }) => {
192                self.check_impl_trait(ty, false)
193            }
194
195            _ => {}
196        }
197
198        visit::walk_item(self, i);
199    }
200
201    fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
202        match i.kind {
203            ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
204                let symbol_name = if let Some(link_name) =
205                    attr::first_attr_value_str_by_name(&i.attrs, sym::link_name)
206                {
207                    link_name
208                } else {
209                    i.kind.ident().unwrap().name
210                };
211
212                let name = symbol_name.as_str();
213                if name.starts_with("llvm.") {
214                    {
    if !self.features.link_llvm_intrinsics() &&
            !i.span.allows_unstable(sym::link_llvm_intrinsics) {
        feature_err(self.sess, sym::link_llvm_intrinsics, i.span,
                "linking to LLVM intrinsics is experimental").emit();
    }
};gate!(
215                        self,
216                        link_llvm_intrinsics,
217                        i.span,
218                        "linking to LLVM intrinsics is experimental"
219                    );
220                } else if name.starts_with("__enzyme_") {
221                    {
    if !self.features.link_enzyme_intrinsics() &&
            !i.span.allows_unstable(sym::link_enzyme_intrinsics) {
        feature_err(self.sess, sym::link_enzyme_intrinsics, i.span,
                "linking to Enzyme intrinsics is experimental").emit();
    }
};gate!(
222                        self,
223                        link_enzyme_intrinsics,
224                        i.span,
225                        "linking to Enzyme intrinsics is experimental"
226                    );
227                }
228            }
229            ast::ForeignItemKind::TyAlias(..) => {
230                {
    if !self.features.extern_types() &&
            !i.span.allows_unstable(sym::extern_types) {
        feature_err(self.sess, sym::extern_types, i.span,
                "extern types are experimental").emit();
    }
};gate!(self, extern_types, i.span, "extern types are experimental");
231            }
232            ast::ForeignItemKind::MacCall(..) => {}
233        }
234
235        visit::walk_item(self, i)
236    }
237
238    fn visit_ty(&mut self, ty: &'a ast::Ty) {
239        match &ty.kind {
240            ast::TyKind::FnPtr(fn_ptr_ty) => {
241                // Function pointers cannot be `const`
242                self.check_late_bound_lifetime_defs(&fn_ptr_ty.generic_params);
243            }
244            ast::TyKind::Pat(..) => {
245                {
    if !self.features.pattern_types() &&
            !ty.span.allows_unstable(sym::pattern_types) {
        feature_err(self.sess, sym::pattern_types, ty.span,
                "pattern types are unstable").emit();
    }
};gate!(self, pattern_types, ty.span, "pattern types are unstable");
246            }
247            ast::TyKind::View(..) => {
248                {
    if !self.features.view_types() &&
            !ty.span.allows_unstable(sym::view_types) {
        feature_err(self.sess, sym::view_types, ty.span,
                "view types are unstable").emit();
    }
};gate!(self, view_types, ty.span, "view types are unstable");
249            }
250            _ => {}
251        }
252        visit::walk_ty(self, ty)
253    }
254
255    fn visit_where_predicate_kind(&mut self, kind: &'a ast::WherePredicateKind) {
256        if let ast::WherePredicateKind::BoundPredicate(bound) = kind {
257            // A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
258            self.check_late_bound_lifetime_defs(&bound.bound_generic_params);
259        }
260        visit::walk_where_predicate_kind(self, kind);
261    }
262
263    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
264        if let ast::FnRetTy::Ty(output_ty) = ret_ty {
265            if let ast::TyKind::Never = output_ty.kind {
266                // Do nothing.
267            } else {
268                self.visit_ty(output_ty)
269            }
270        }
271    }
272
273    fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) {
274        visit::walk_generic_args(self, args);
275    }
276
277    fn visit_expr(&mut self, e: &'a ast::Expr) {
278        match e.kind {
279            ast::ExprKind::TryBlock(_, None) => {
280                // `try { ... }` is old and is only gated post-expansion here.
281                {
    if !self.features.try_blocks() && !e.span.allows_unstable(sym::try_blocks)
        {
        feature_err(self.sess, sym::try_blocks, e.span,
                "`try` expression is experimental").emit();
    }
};gate!(self, try_blocks, e.span, "`try` expression is experimental");
282            }
283            ast::ExprKind::TryBlock(_, Some(_)) => {
284                // `try_blocks_heterogeneous` is new, and gated pre-expansion instead.
285            }
286            ast::ExprKind::Lit(token::Lit {
287                kind: token::LitKind::Float | token::LitKind::Integer,
288                suffix,
289                ..
290            }) => match suffix {
291                Some(sym::f16) => {
292                    {
    if !self.features.f16() && !e.span.allows_unstable(sym::f16) {
        feature_err(self.sess, sym::f16, e.span,
                "the type `f16` is unstable").emit();
    }
}gate!(self, f16, e.span, "the type `f16` is unstable")
293                }
294                Some(sym::f128) => {
295                    {
    if !self.features.f128() && !e.span.allows_unstable(sym::f128) {
        feature_err(self.sess, sym::f128, e.span,
                "the type `f128` is unstable").emit();
    }
}gate!(self, f128, e.span, "the type `f128` is unstable")
296                }
297                _ => (),
298            },
299            _ => {}
300        }
301        visit::walk_expr(self, e)
302    }
303
304    fn visit_pat(&mut self, pattern: &'a ast::Pat) {
305        match &pattern.kind {
306            PatKind::Slice(pats) => {
307                for pat in pats {
308                    let inner_pat = match &pat.kind {
309                        PatKind::Ident(.., Some(pat)) => pat,
310                        _ => pat,
311                    };
312                    if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
313                        {
    if !self.features.half_open_range_patterns_in_slices() &&
            !pat.span.allows_unstable(sym::half_open_range_patterns_in_slices)
        {
        feature_err(self.sess, sym::half_open_range_patterns_in_slices,
                pat.span, "`X..` patterns in slices are experimental").emit();
    }
};gate!(
314                            self,
315                            half_open_range_patterns_in_slices,
316                            pat.span,
317                            "`X..` patterns in slices are experimental"
318                        );
319                    }
320                }
321            }
322            _ => {}
323        }
324        visit::walk_pat(self, pattern)
325    }
326
327    fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
328        self.check_late_bound_lifetime_defs(&t.bound_generic_params);
329        visit::walk_poly_trait_ref(self, t);
330    }
331
332    fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, _: Span, _: NodeId) {
333        if let Some(_header) = fn_kind.header() {
334            // Stability of const fn methods are covered in `visit_assoc_item` below.
335        }
336
337        if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
338            self.check_late_bound_lifetime_defs(generic_params);
339        }
340
341        visit::walk_fn(self, fn_kind)
342    }
343
344    fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
345        let is_fn = match &i.kind {
346            ast::AssocItemKind::Fn(_) => true,
347            ast::AssocItemKind::Type(ast::TyAlias { ty, .. }) => {
348                if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
349                    {
    if !self.features.associated_type_defaults() &&
            !i.span.allows_unstable(sym::associated_type_defaults) {
        feature_err(self.sess, sym::associated_type_defaults, i.span,
                "associated type defaults are unstable").emit();
    }
};gate!(
350                        self,
351                        associated_type_defaults,
352                        i.span,
353                        "associated type defaults are unstable"
354                    );
355                }
356                if let Some(ty) = ty {
357                    self.check_impl_trait(ty, true);
358                }
359                false
360            }
361            ast::AssocItemKind::Const(ast::ConstItem { body: Some(_), .. }) => {
362                if ctxt == AssocCtxt::Trait && attr::contains_name(&i.attrs, sym::rustc_always_gca)
363                {
364                    {
    if !self.features.associated_type_defaults() &&
            !i.span.allows_unstable(sym::associated_type_defaults) {
        feature_err(self.sess, sym::associated_type_defaults, i.span,
                "associated type defaults are unstable").emit();
    }
};gate!(
365                        self,
366                        associated_type_defaults,
367                        i.span,
368                        "associated type defaults are unstable"
369                    );
370                }
371                false
372            }
373            _ => false,
374        };
375        if let ast::Defaultness::Default(_) = i.kind.defaultness() {
376            // Limit `min_specialization` to only specializing functions.
377            {
    if !(self.features.specialization() ||
                    (is_fn && self.features.min_specialization())) &&
            !i.span.allows_unstable(sym::specialization) {
        #[allow(unused_mut)]
        let mut diag =
            feature_err((&self).sess, sym::specialization, i.span,
                "specialization is experimental");
        diag.emit();
    }
};gate_alt!(
378                &self,
379                self.features.specialization() || (is_fn && self.features.min_specialization()),
380                sym::specialization,
381                i.span,
382                "specialization is experimental"
383            );
384        }
385        visit::walk_assoc_item(self, i, ctxt)
386    }
387
388    fn visit_test_binder_forall(&mut self, forall: &'a ast::TestBinderForall) {
389        self.check_late_bound_lifetime_defs(&forall.generics.params);
390        visit::walk_test_binder_forall(self, forall)
391    }
392
393    fn visit_test_binder_exists(&mut self, exists: &'a ast::TestBinderExists) {
394        self.check_late_bound_lifetime_defs(&exists.params);
395        visit::walk_test_binder_exists(self, exists)
396    }
397
398    fn visit_test_binder_bound_type_constraint(
399        &mut self,
400        bound_type: &'a ast::TestBinderBoundTypeConstraint,
401    ) -> Self::Result {
402        self.check_late_bound_lifetime_defs(&bound_type.params);
403        visit::walk_test_binder_bound_type_constraint(self, bound_type)
404    }
405}
406
407// -----------------------------------------------------------------------------
408
409pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
410    maybe_stage_features(sess, features, krate);
411    check_incompatible_features(sess, features);
412    check_dependent_features(sess, features);
413    warn_next_solver_and_gce(sess, features);
414    warn_next_solver_and_higher_ranked_assumptions(sess);
415    check_features_requiring_new_solver(sess, features);
416
417    let mut visitor = PostExpansionVisitor { sess, features };
418
419    // -----------------------------------------------------------------------------
420    // PRE-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX
421    // -----------------------------------------------------------------------------
422
423    let spans = sess.psess.gated_spans.spans.borrow();
424    macro_rules! gate_all {
425        ($feature:ident, $explain:literal $(, $help:literal)?) => {
426            for &span in spans.get(&sym::$feature).into_flat_iter() {
427                gate!(visitor, $feature, span, $explain $(, $help)?);
428            }
429        };
430    }
431
432    // tidy-alphabetical-start
433    for &span in spans.get(&sym::async_for_loop).into_flat_iter() {
    {
        if !visitor.features.async_for_loop() &&
                !span.allows_unstable(sym::async_for_loop) {
            feature_err(visitor.sess, sym::async_for_loop, span,
                    "`for await` loops are experimental").emit();
        }
    };
};gate_all!(async_for_loop, "`for await` loops are experimental");
434    for &span in spans.get(&sym::builtin_syntax).into_flat_iter() {
    {
        if !visitor.features.builtin_syntax() &&
                !span.allows_unstable(sym::builtin_syntax) {
            feature_err(visitor.sess, sym::builtin_syntax, span,
                    "`builtin #` syntax is unstable").emit();
        }
    };
};gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
435    for &span in spans.get(&sym::const_block_items).into_flat_iter() {
    {
        if !visitor.features.const_block_items() &&
                !span.allows_unstable(sym::const_block_items) {
            feature_err(visitor.sess, sym::const_block_items, span,
                    "const block items are experimental").emit();
        }
    };
};gate_all!(const_block_items, "const block items are experimental");
436    for &span in spans.get(&sym::const_closures).into_flat_iter() {
    {
        if !visitor.features.const_closures() &&
                !span.allows_unstable(sym::const_closures) {
            feature_err(visitor.sess, sym::const_closures, span,
                    "const closures are experimental").emit();
        }
    };
};gate_all!(const_closures, "const closures are experimental");
437    for &span in spans.get(&sym::const_trait_impl).into_flat_iter() {
    {
        if !visitor.features.const_trait_impl() &&
                !span.allows_unstable(sym::const_trait_impl) {
            feature_err(visitor.sess, sym::const_trait_impl, span,
                    "const trait impls are experimental").emit();
        }
    };
};gate_all!(const_trait_impl, "const trait impls are experimental");
438    for &span in spans.get(&sym::contracts).into_flat_iter() {
    {
        if !visitor.features.contracts() &&
                !span.allows_unstable(sym::contracts) {
            feature_err(visitor.sess, sym::contracts, span,
                    "contracts are incomplete").emit();
        }
    };
};gate_all!(contracts, "contracts are incomplete");
439    for &span in spans.get(&sym::contracts_internals).into_flat_iter() {
    {
        if !visitor.features.contracts_internals() &&
                !span.allows_unstable(sym::contracts_internals) {
            feature_err(visitor.sess, sym::contracts_internals, span,
                    "contract internal machinery is for internal use only").emit();
        }
    };
};gate_all!(contracts_internals, "contract internal machinery is for internal use only");
440    for &span in spans.get(&sym::coroutines).into_flat_iter() {
    {
        if !visitor.features.coroutines() &&
                !span.allows_unstable(sym::coroutines) {
            feature_err(visitor.sess, sym::coroutines, span,
                    "coroutine syntax is experimental").emit();
        }
    };
};gate_all!(coroutines, "coroutine syntax is experimental");
441    for &span in spans.get(&sym::default_field_values).into_flat_iter() {
    {
        if !visitor.features.default_field_values() &&
                !span.allows_unstable(sym::default_field_values) {
            feature_err(visitor.sess, sym::default_field_values, span,
                    "default values on fields are experimental").emit();
        }
    };
};gate_all!(default_field_values, "default values on fields are experimental");
442    for &span in spans.get(&sym::ergonomic_clones).into_flat_iter() {
    {
        if !visitor.features.ergonomic_clones() &&
                !span.allows_unstable(sym::ergonomic_clones) {
            feature_err(visitor.sess, sym::ergonomic_clones, span,
                    "ergonomic clones are experimental").emit();
        }
    };
};gate_all!(ergonomic_clones, "ergonomic clones are experimental");
443    for &span in spans.get(&sym::explicit_tail_calls).into_flat_iter() {
    {
        if !visitor.features.explicit_tail_calls() &&
                !span.allows_unstable(sym::explicit_tail_calls) {
            feature_err(visitor.sess, sym::explicit_tail_calls, span,
                    "`become` expression is experimental").emit();
        }
    };
};gate_all!(explicit_tail_calls, "`become` expression is experimental");
444    for &span in spans.get(&sym::final_associated_functions).into_flat_iter() {
    {
        if !visitor.features.final_associated_functions() &&
                !span.allows_unstable(sym::final_associated_functions) {
            feature_err(visitor.sess, sym::final_associated_functions, span,
                    "`final` on trait functions is experimental").emit();
        }
    };
};gate_all!(final_associated_functions, "`final` on trait functions is experimental");
445    for &span in spans.get(&sym::fn_delegation).into_flat_iter() {
    {
        if !visitor.features.fn_delegation() &&
                !span.allows_unstable(sym::fn_delegation) {
            feature_err(visitor.sess, sym::fn_delegation, span,
                    "functions delegation is not yet fully implemented").emit();
        }
    };
};gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
446    for &span in spans.get(&sym::forced_keywords).into_flat_iter() {
    {
        if !visitor.features.forced_keywords() &&
                !span.allows_unstable(sym::forced_keywords) {
            feature_err(visitor.sess, sym::forced_keywords, span,
                    "forced keywords are experimental").emit();
        }
    };
};gate_all!(forced_keywords, "forced keywords are experimental");
447    for &span in spans.get(&sym::frontmatter).into_flat_iter() {
    {
        if !visitor.features.frontmatter() &&
                !span.allows_unstable(sym::frontmatter) {
            feature_err(visitor.sess, sym::frontmatter, span,
                    "frontmatters are experimental").emit();
        }
    };
};gate_all!(frontmatter, "frontmatters are experimental");
448    for &span in spans.get(&sym::function_arg_const_generics).into_flat_iter() {
    {
        if !visitor.features.function_arg_const_generics() &&
                !span.allows_unstable(sym::function_arg_const_generics) {
            feature_err(visitor.sess, sym::function_arg_const_generics, span,
                    "function arg const generics are experimental").emit();
        }
    };
};gate_all!(function_arg_const_generics, "function arg const generics are experimental");
449    for &span in spans.get(&sym::gca_min_const_items).into_flat_iter() {
    {
        if !visitor.features.gca_min_const_items() &&
                !span.allows_unstable(sym::gca_min_const_items) {
            feature_err(visitor.sess, sym::gca_min_const_items, span,
                    "unbraced const blocks as const args are experimental").emit();
        }
    };
};gate_all!(gca_min_const_items, "unbraced const blocks as const args are experimental");
450    for &span in spans.get(&sym::gen_blocks).into_flat_iter() {
    {
        if !visitor.features.gen_blocks() &&
                !span.allows_unstable(sym::gen_blocks) {
            feature_err(visitor.sess, sym::gen_blocks, span,
                    "gen blocks are experimental").emit();
        }
    };
};gate_all!(gen_blocks, "gen blocks are experimental");
451    for &span in spans.get(&sym::generic_const_items).into_flat_iter() {
    {
        if !visitor.features.generic_const_items() &&
                !span.allows_unstable(sym::generic_const_items) {
            feature_err(visitor.sess, sym::generic_const_items, span,
                    "generic const items are experimental").emit();
        }
    };
};gate_all!(generic_const_items, "generic const items are experimental");
452    for &span in spans.get(&sym::global_registration).into_flat_iter() {
    {
        if !visitor.features.global_registration() &&
                !span.allows_unstable(sym::global_registration) {
            feature_err(visitor.sess, sym::global_registration, span,
                    "global registration is experimental").emit();
        }
    };
};gate_all!(global_registration, "global registration is experimental");
453    for &span in spans.get(&sym::guard_patterns).into_flat_iter() {
    {
        if !visitor.features.guard_patterns() &&
                !span.allows_unstable(sym::guard_patterns) {
            feature_err(visitor.sess, sym::guard_patterns, span,
                        "guard patterns are experimental").with_help("consider using match arm guards").emit();
        }
    };
};gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
454    for &span in spans.get(&sym::impl_restriction).into_flat_iter() {
    {
        if !visitor.features.impl_restriction() &&
                !span.allows_unstable(sym::impl_restriction) {
            feature_err(visitor.sess, sym::impl_restriction, span,
                    "`impl` restrictions are experimental").emit();
        }
    };
};gate_all!(impl_restriction, "`impl` restrictions are experimental");
455    for &span in spans.get(&sym::more_qualified_paths).into_flat_iter() {
    {
        if !visitor.features.more_qualified_paths() &&
                !span.allows_unstable(sym::more_qualified_paths) {
            feature_err(visitor.sess, sym::more_qualified_paths, span,
                    "usage of qualified paths in this context is experimental").emit();
        }
    };
};gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
456    for &span in spans.get(&sym::move_expr).into_flat_iter() {
    {
        if !visitor.features.move_expr() &&
                !span.allows_unstable(sym::move_expr) {
            feature_err(visitor.sess, sym::move_expr, span,
                    "`move(expr)` syntax is experimental").emit();
        }
    };
};gate_all!(move_expr, "`move(expr)` syntax is experimental");
457    for &span in spans.get(&sym::mut_ref).into_flat_iter() {
    {
        if !visitor.features.mut_ref() && !span.allows_unstable(sym::mut_ref)
            {
            feature_err(visitor.sess, sym::mut_ref, span,
                    "mutable by-reference bindings are experimental").emit();
        }
    };
};gate_all!(mut_ref, "mutable by-reference bindings are experimental");
458    for &span in spans.get(&sym::mut_restriction).into_flat_iter() {
    {
        if !visitor.features.mut_restriction() &&
                !span.allows_unstable(sym::mut_restriction) {
            feature_err(visitor.sess, sym::mut_restriction, span,
                    "`mut` restrictions are experimental").emit();
        }
    };
};gate_all!(mut_restriction, "`mut` restrictions are experimental");
459    for &span in spans.get(&sym::pin_ergonomics).into_flat_iter() {
    {
        if !visitor.features.pin_ergonomics() &&
                !span.allows_unstable(sym::pin_ergonomics) {
            feature_err(visitor.sess, sym::pin_ergonomics, span,
                    "pinned reference syntax is experimental").emit();
        }
    };
};gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
460    for &span in spans.get(&sym::postfix_match).into_flat_iter() {
    {
        if !visitor.features.postfix_match() &&
                !span.allows_unstable(sym::postfix_match) {
            feature_err(visitor.sess, sym::postfix_match, span,
                    "postfix match is experimental").emit();
        }
    };
};gate_all!(postfix_match, "postfix match is experimental");
461    for &span in spans.get(&sym::return_type_notation).into_flat_iter() {
    {
        if !visitor.features.return_type_notation() &&
                !span.allows_unstable(sym::return_type_notation) {
            feature_err(visitor.sess, sym::return_type_notation, span,
                    "return type notation is experimental").emit();
        }
    };
};gate_all!(return_type_notation, "return type notation is experimental");
462    for &span in spans.get(&sym::splat).into_flat_iter() {
    {
        if !visitor.features.splat() && !span.allows_unstable(sym::splat) {
            feature_err(visitor.sess, sym::splat, span,
                        "`fn(#[rustc_splat] (a, ...))` is incomplete").with_help("call as func((a, ...)) instead").emit();
        }
    };
};gate_all!(
463        splat,
464        "`fn(#[rustc_splat] (a, ...))` is incomplete",
465        "call as func((a, ...)) instead"
466    );
467    for &span in spans.get(&sym::super_let).into_flat_iter() {
    {
        if !visitor.features.super_let() &&
                !span.allows_unstable(sym::super_let) {
            feature_err(visitor.sess, sym::super_let, span,
                    "`super let` is experimental").emit();
        }
    };
};gate_all!(super_let, "`super let` is experimental");
468    for &span in spans.get(&sym::try_blocks_heterogeneous).into_flat_iter() {
    {
        if !visitor.features.try_blocks_heterogeneous() &&
                !span.allows_unstable(sym::try_blocks_heterogeneous) {
            feature_err(visitor.sess, sym::try_blocks_heterogeneous, span,
                    "`try bikeshed` expression is experimental").emit();
        }
    };
};gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
469    for &span in spans.get(&sym::unnamed_enum_variants).into_flat_iter() {
    {
        if !visitor.features.unnamed_enum_variants() &&
                !span.allows_unstable(sym::unnamed_enum_variants) {
            feature_err(visitor.sess, sym::unnamed_enum_variants, span,
                    "unnamed enum variants are experimental").emit();
        }
    };
};gate_all!(unnamed_enum_variants, "unnamed enum variants are experimental");
470    for &span in spans.get(&sym::unsafe_binders).into_flat_iter() {
    {
        if !visitor.features.unsafe_binders() &&
                !span.allows_unstable(sym::unsafe_binders) {
            feature_err(visitor.sess, sym::unsafe_binders, span,
                    "unsafe binder types are experimental").emit();
        }
    };
};gate_all!(unsafe_binders, "unsafe binder types are experimental");
471    for &span in spans.get(&sym::unsafe_fields).into_flat_iter() {
    {
        if !visitor.features.unsafe_fields() &&
                !span.allows_unstable(sym::unsafe_fields) {
            feature_err(visitor.sess, sym::unsafe_fields, span,
                    "`unsafe` fields are experimental").emit();
        }
    };
};gate_all!(unsafe_fields, "`unsafe` fields are experimental");
472    for &span in spans.get(&sym::view_types).into_flat_iter() {
    {
        if !visitor.features.view_types() &&
                !span.allows_unstable(sym::view_types) {
            feature_err(visitor.sess, sym::view_types, span,
                    "view types are experimental").emit();
        }
    };
};gate_all!(view_types, "view types are experimental");
473    for &span in spans.get(&sym::where_clause_attrs).into_flat_iter() {
    {
        if !visitor.features.where_clause_attrs() &&
                !span.allows_unstable(sym::where_clause_attrs) {
            feature_err(visitor.sess, sym::where_clause_attrs, span,
                    "attributes in `where` clause are unstable").emit();
        }
    };
};gate_all!(where_clause_attrs, "attributes in `where` clause are unstable");
474    for &span in spans.get(&sym::yeet_expr).into_flat_iter() {
    {
        if !visitor.features.yeet_expr() &&
                !span.allows_unstable(sym::yeet_expr) {
            feature_err(visitor.sess, sym::yeet_expr, span,
                    "`do yeet` expression is experimental").emit();
        }
    };
};gate_all!(yeet_expr, "`do yeet` expression is experimental");
475    // tidy-alphabetical-end
476
477    for &span in spans.get(&sym::async_trait_bounds).into_flat_iter() {
    {
        if !visitor.features.async_trait_bounds() &&
                !span.allows_unstable(sym::async_trait_bounds) {
            feature_err(visitor.sess, sym::async_trait_bounds, span,
                        "`async` trait bounds are unstable").with_help("use the desugared name of the async trait, such as `AsyncFn`").emit();
        }
    };
};gate_all!(
478        async_trait_bounds,
479        "`async` trait bounds are unstable",
480        "use the desugared name of the async trait, such as `AsyncFn`"
481    );
482    for &span in spans.get(&sym::closure_lifetime_binder).into_flat_iter() {
    {
        if !visitor.features.closure_lifetime_binder() &&
                !span.allows_unstable(sym::closure_lifetime_binder) {
            feature_err(visitor.sess, sym::closure_lifetime_binder, span,
                        "`for<...>` binders for closures are experimental").with_help("consider using a type annotation instead: \
         `let closure: for<...> fn(...) -> ... = /* closure */;`").emit();
        }
    };
};gate_all!(
483        closure_lifetime_binder,
484        "`for<...>` binders for closures are experimental",
485        "consider using a type annotation instead: \
486         `let closure: for<...> fn(...) -> ... = /* closure */;`"
487    );
488    for &span in
    spans.get(&sym::half_open_range_patterns_in_slices).into_flat_iter() {
    {
        if !visitor.features.half_open_range_patterns_in_slices() &&
                !span.allows_unstable(sym::half_open_range_patterns_in_slices)
            {
            feature_err(visitor.sess, sym::half_open_range_patterns_in_slices,
                    span,
                    "half-open range patterns in slices are unstable").emit();
        }
    };
};gate_all!(
489        half_open_range_patterns_in_slices,
490        "half-open range patterns in slices are unstable"
491    );
492    for &span in spans.get(&sym::named_fn_trait_parameters).into_flat_iter() {
    {
        if !visitor.features.named_fn_trait_parameters() &&
                !span.allows_unstable(sym::named_fn_trait_parameters) {
            feature_err(visitor.sess, sym::named_fn_trait_parameters, span,
                    "named parameters in parenthesized generic argument lists are experimental").emit();
        }
    };
};gate_all!(
493        named_fn_trait_parameters,
494        "named parameters in parenthesized generic argument lists are experimental"
495    );
496
497    // `associated_const_equality` will be stabilized as part of `gca_min_const_items`.
498    for &span in spans.get(&sym::associated_const_equality).into_flat_iter() {
499        {
    if !visitor.features.gca_min_const_items() &&
            !span.allows_unstable(sym::gca_min_const_items) {
        feature_err(visitor.sess, sym::gca_min_const_items, span,
                "associated const equality is incomplete").emit();
    }
};gate!(visitor, gca_min_const_items, span, "associated const equality is incomplete");
500    }
501
502    // Negative bounds are *super* internal. We require `-Zinternal-testing-features` *and*
503    // `#![feature(negative_bounds)]` to prevent proliferation. Under no circumstances do we
504    // want to advertise the flag and the feature name to users!
505    //
506    // IMPORTANT: If you intend on turning negative bounds into a public-facing feature, please
507    //            consult T-types and T-lang first! Do **not** just remove the `-Z` check!
508    //
509    // NOTE: `T: !Bound` means "`T` implements `Bound` negatively",
510    //       it does **not** mean "`T` doesn't implement `Bound` (positively or negatively)"!
511    //       The latter would be a SemVer hazard!
512    if !sess.opts.unstable_opts.internal_testing_features || !visitor.features.negative_bounds() {
513        for &span in spans.get(&sym::negative_bounds).into_flat_iter() {
514            sess.dcx().emit_err(diagnostics::NegativeBoundUnsupported { span });
515        }
516    }
517
518    if !visitor.features.never_patterns() {
519        for &span in spans.get(&sym::never_patterns).into_flat_iter() {
520            if span.allows_unstable(sym::never_patterns) {
521                continue;
522            }
523            // We gate two types of spans: the span of a `!` pattern, and the span of a
524            // match arm without a body. For the latter we want to give the user a normal
525            // error.
526            if let Ok("!") = sess.source_map().span_to_snippet(span).as_deref() {
527                feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
528                    .emit();
529            } else {
530                let suggestion = span.shrink_to_hi();
531                sess.dcx().emit_err(diagnostics::MatchArmWithNoBody { span, suggestion });
532            }
533        }
534    }
535
536    // Yield exprs can be enabled either by `yield_expr`, by `coroutines` or by `gen_blocks`.
537    for &span in spans.get(&sym::yield_expr).into_flat_iter() {
538        if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
539            && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
540            && (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
541        {
542            // Only mentioned `yield_expr` in the diagnostic since that'll be sufficient.
543            // You can think of it as `coroutines` and `gen_blocks` implying `yield_expr`.
544            feature_err(visitor.sess, sym::yield_expr, span, "yield syntax is experimental").emit();
545        }
546    }
547
548    // -----------------------------------------------------------------------------
549    // **LEGACY**  SOFT PRE-EXPANSION FEATURE GATES FOR UNSTABLE SYNTAX  **LEGACY**
550    // -----------------------------------------------------------------------------
551
552    // IMPORTANT: Do not extend the list below! New syntax should go above and use `gate_all`.
553
554    // FIXME(#154045): Migrate all of these to erroring feature gates and
555    //                 remove the corresponding post-expansion feature gates.
556
557    macro_rules! soft_gate_all_legacy_dont_use {
558        ($feature:ident, $explain:literal) => {
559            for &span in spans.get(&sym::$feature).into_flat_iter() {
560                if !visitor.features.$feature() && !span.allows_unstable(sym::$feature) {
561                    feature_warn(&visitor.sess, sym::$feature, span, $explain);
562                }
563            }
564        };
565    }
566
567    // tidy-alphabetical-start
568    for &span in spans.get(&sym::auto_traits).into_flat_iter() {
    if !visitor.features.auto_traits() &&
            !span.allows_unstable(sym::auto_traits) {
        feature_warn(&visitor.sess, sym::auto_traits, span,
            "`auto` traits are unstable");
    }
};soft_gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable");
569    for &span in spans.get(&sym::decl_macro).into_flat_iter() {
    if !visitor.features.decl_macro() &&
            !span.allows_unstable(sym::decl_macro) {
        feature_warn(&visitor.sess, sym::decl_macro, span,
            "`macro` is experimental");
    }
};soft_gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
570    for &span in spans.get(&sym::negative_impls).into_flat_iter() {
    if !visitor.features.negative_impls() &&
            !span.allows_unstable(sym::negative_impls) {
        feature_warn(&visitor.sess, sym::negative_impls, span,
            "negative impls are experimental");
    }
};soft_gate_all_legacy_dont_use!(negative_impls, "negative impls are experimental");
571    for &span in spans.get(&sym::specialization).into_flat_iter() {
    if !visitor.features.specialization() &&
            !span.allows_unstable(sym::specialization) {
        feature_warn(&visitor.sess, sym::specialization, span,
            "specialization is experimental");
    }
};soft_gate_all_legacy_dont_use!(specialization, "specialization is experimental");
572    for &span in spans.get(&sym::trait_alias).into_flat_iter() {
    if !visitor.features.trait_alias() &&
            !span.allows_unstable(sym::trait_alias) {
        feature_warn(&visitor.sess, sym::trait_alias, span,
            "trait aliases are experimental");
    }
};soft_gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
573    for &span in spans.get(&sym::try_blocks).into_flat_iter() {
    if !visitor.features.try_blocks() &&
            !span.allows_unstable(sym::try_blocks) {
        feature_warn(&visitor.sess, sym::try_blocks, span,
            "`try` blocks are unstable");
    }
};soft_gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
574    // tidy-alphabetical-end
575
576    for &span in spans.get(&sym::min_specialization).into_flat_iter() {
577        if !visitor.features.specialization()
578            && !visitor.features.min_specialization()
579            && !span.allows_unstable(sym::specialization)
580            && !span.allows_unstable(sym::min_specialization)
581        {
582            feature_warn(visitor.sess, sym::specialization, span, "specialization is experimental");
583        }
584    }
585
586    // -----------------------------------------------------------------------------
587
588    visit::walk_crate(&mut visitor, krate);
589}
590
591fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
592    // checks if `#![feature]` has been used to enable any feature.
593    if sess.opts.unstable_features.is_nightly_build() {
594        return;
595    }
596    if features.enabled_features().is_empty() {
597        return;
598    }
599    let mut errored = false;
600
601    if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
602        AttributeParser::parse_limited_sym(sess, &krate.attrs, &[sym::feature])
603    {
604        // `feature(...)` used on non-nightly. This is definitely an error.
605        let mut err = diagnostics::FeatureOnNonNightly {
606            span: first_span,
607            channel: ::core::option::Option::Some("nightly")option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
608            stable_features: ::alloc::vec::Vec::new()vec![],
609            sugg: None,
610        };
611
612        let mut all_stable = true;
613        for ident in feature_idents {
614            let name = ident.name;
615            let stable_since = features
616                .enabled_lang_features()
617                .iter()
618                .find(|feat| feat.gate_name == name)
619                .map(|feat| feat.stable_since)
620                .flatten();
621            if let Some(since) = stable_since {
622                err.stable_features.push(diagnostics::StableFeature { name, since });
623            } else {
624                all_stable = false;
625            }
626        }
627        if all_stable {
628            err.sugg = Some(first_span);
629        }
630        sess.dcx().emit_err(err);
631        errored = true;
632    }
633    // Just make sure we actually error if anything is listed in `enabled_features`.
634    if !errored { ::core::panicking::panic("assertion failed: errored") };assert!(errored);
635}
636
637fn check_incompatible_features(sess: &Session, features: &Features) {
638    let enabled_features = features.enabled_features_iter_stable_order();
639
640    for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
641        .iter()
642        .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
643    {
644        if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1)
645            && let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
646        {
647            let spans = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [f1_span, f2_span]))vec![f1_span, f2_span];
648            sess.dcx().emit_err(diagnostics::IncompatibleFeatures {
649                spans,
650                f1: f1_name,
651                f2: f2_name,
652            });
653        }
654    }
655}
656
657fn check_dependent_features(sess: &Session, features: &Features) {
658    for &(parent, ref children) in
659        rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, children)| {
660            features.enabled(*parent) && !check_enabled(features, children)
661        })
662    {
663        let parent_span = features
664            .enabled_features_iter_stable_order()
665            .find_map(|(name, span)| (name == parent).then_some(span))
666            .unwrap();
667        // FIXME: should probably format this in fluent instead of here
668        let missing = format(features, &children);
669        sess.dcx().emit_err(diagnostics::MissingDependentFeatures { parent_span, parent, missing });
670    }
671
672    fn check_enabled(features: &Features, feature: &DependentFeature) -> bool {
673        match feature {
674            DependentFeature::And(children) => {
675                children.iter().all(|child| check_enabled(features, child))
676            }
677            DependentFeature::Or(children) => {
678                children.iter().any(|child| check_enabled(features, child))
679            }
680            DependentFeature::Leaf(symbol) => features.enabled(*symbol),
681        }
682    }
683
684    fn format(features: &Features, feature: &DependentFeature) -> String {
685        // FIXME: parentheses/precedence
686        match feature {
687            DependentFeature::And(children) => children
688                .iter()
689                .filter(|child| !check_enabled(features, child))
690                .map(|child| format(features, child))
691                .intersperse(String::from(" and "))
692                .collect(),
693            DependentFeature::Or(children) => children
694                .iter()
695                .map(|child| format(features, child))
696                .intersperse(String::from(" or "))
697                .collect(),
698            DependentFeature::Leaf(symbol) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", symbol.as_str()))
    })format!("`{}`", symbol.as_str()),
699        }
700    }
701}
702
703fn warn_next_solver_and_gce(sess: &Session, features: &Features) {
704    if sess.opts.unstable_opts.next_solver != NextSolverConfig::Globally {
705        return;
706    }
707
708    // Warn people who use GCE and -Znext-solver=globally
709    // that their trait solver was downgraded to -Znext-solver=coherence
710    if let Some(gce_span) = features
711        .enabled_lang_features()
712        .iter()
713        .find(|feat| feat.gate_name == sym::generic_const_exprs)
714        .map(|feat| feat.attr_sp)
715    {
716        sess.dcx()
717            .emit_warn(diagnostics::NextSolverDisabledForGenericConstExprs { span: gce_span });
718    }
719}
720
721fn warn_next_solver_and_higher_ranked_assumptions(sess: &Session) {
722    // Warn people who use -Zhigher-ranked-assumptions and -Znext-solver=globally
723    // that their trait solver was downgraded to -Znext-solver=coherence
724    if sess.opts.unstable_opts.next_solver == NextSolverConfig::Globally
725        && sess.opts.unstable_opts.higher_ranked_assumptions
726    {
727        sess.dcx().emit_warn(diagnostics::NextSolverDisabledForHigherRankedAssumptions);
728    }
729}
730
731fn check_features_requiring_new_solver(sess: &Session, features: &Features) {
732    if sess.opts.unstable_opts.next_solver == NextSolverConfig::Globally {
733        return;
734    }
735
736    // Require the new solver with GCA, because the old solver can't implement GCA correctly as it
737    // does not support normalization obligations for free and inherent consts.
738    if let Some(gca_span) = features
739        .enabled_lang_features()
740        .iter()
741        .find(|feat| feat.gate_name == sym::gca_const_items)
742        .map(|feat| feat.attr_sp)
743    {
744        #[allow(rustc::symbol_intern_string_literal)]
745        sess.dcx().emit_err(diagnostics::MissingDependentFeatures {
746            parent_span: gca_span,
747            parent: sym::gca_const_items,
748            missing: String::from("-Znext-solver=globally"),
749        });
750    }
751}