From 8b5be2b271010576a22e168103206b683aab0065 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Tue, 3 Feb 2026 22:35:09 +0100 Subject: [PATCH 1/5] Implement stdio FD constants --- library/std/src/os/fd/mod.rs | 5 ++++ library/std/src/os/fd/stdio.rs | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 library/std/src/os/fd/stdio.rs diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index 95cf4932e6e2c..473d7ae3e2ae6 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -16,6 +16,9 @@ mod owned; #[cfg(not(target_os = "trusty"))] mod net; +// Implementation of stdio file descriptor constants. +mod stdio; + #[cfg(test)] mod tests; @@ -24,3 +27,5 @@ mod tests; pub use owned::*; #[stable(feature = "os_fd", since = "1.66.0")] pub use raw::*; +#[unstable(feature = "stdio_fd_consts", issue = "150836")] +pub use stdio::*; diff --git a/library/std/src/os/fd/stdio.rs b/library/std/src/os/fd/stdio.rs new file mode 100644 index 0000000000000..c50cbd39849b7 --- /dev/null +++ b/library/std/src/os/fd/stdio.rs @@ -0,0 +1,53 @@ +use super::BorrowedFd; + +/// The file descriptor for the standard input stream of the current process. +/// +/// See [`io::stdin()`][`crate::io::stdin`] for the higher level handle, which should be preferred +/// whenever possible. See [`STDERR`] for why the file descriptor might be required and caveats. +#[unstable(feature = "stdio_fd_consts", issue = "150836")] +pub const STDIN: BorrowedFd<'static> = unsafe { BorrowedFd::borrow_raw(0) }; + +/// The file descriptor for the standard output stream of the current process. +/// +/// See [`io::stdout()`][`crate::io::stdout`] for the higher level handle, which should be preferred +/// whenever possible. See [`STDERR`] for why the file descriptor might be required and caveats. In +/// addition to the issues discussed there, note that [`Stdout`][`crate::io::Stdout`] is buffered by +/// default, and writing to the file descriptor will bypass this buffer. +#[unstable(feature = "stdio_fd_consts", issue = "150836")] +pub const STDOUT: BorrowedFd<'static> = unsafe { BorrowedFd::borrow_raw(1) }; + +/// The file descriptor for the standard error stream of the current process. +/// +/// See [`io::stderr()`][`crate::io::stderr`] for the higher level handle, which should be preferred +/// whenever possible. However, there are situations where touching the `std::io` handles (or most +/// other parts of the standard library) risks deadlocks or other subtle bugs. For example: +/// +/// - Global allocators must be careful to [avoid reentrancy][global-alloc-reentrancy], and the +/// `std::io` handles may allocate memory on (some) accesses. +/// - Signal handlers must be *async-signal-safe*, which rules out panicking, taking locks (may +/// deadlock if the signal handler interrupted a thread holding that lock), allocating memory, or +/// anything else that is not explicitly declared async-signal-safe. +/// - `CommandExt::pre_exec` callbacks can safely panic (with some limitations), but otherwise must +/// abide by similar limitations as signal handlers. In particular, at the time these callbacks +/// run, the stdio file descriptors have already been replaced, but the locks protecting the +/// `std::io` handles may be permanently locked if another thread held the lock at `fork()` time. +/// +/// In these and similar cases, direct access to the file descriptor may be required. However, in +/// most cases, using the `std::io` handles and accessing the file descriptor via the `AsFd` +/// implementations is preferable, as it enables cooperation with the standard library's locking and +/// buffering. +/// +/// # I/O safety +/// +/// This is a `BorrowedFd<'static>` because the standard input/output/error streams are shared +/// resources that must remain available for the lifetime of the process. This is only true when +/// linking `std`, and may not always hold for [code running before `main()`][before-after-main] or +/// in `no_std` environments. It is [unsound][io-safety] to close these file descriptors. Safe +/// patterns for changing these file descriptors are available on Unix via the `StdioExt` extension +/// trait. +/// +/// [before-after-main]: ../../../std/index.html#use-before-and-after-main +/// [io-safety]: ../../../std/io/index.html#io-safety +/// [global-alloc-reentrancy]: ../../../std/alloc/trait.GlobalAlloc.html#re-entrance +#[unstable(feature = "stdio_fd_consts", issue = "150836")] +pub const STDERR: BorrowedFd<'static> = unsafe { BorrowedFd::borrow_raw(2) }; From 9a30ec81498592914950d7a63253965e61d8cc05 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 7 Jan 2026 15:22:47 -0800 Subject: [PATCH 2/5] Implement MVP for opaque generic const arguments This is meant to be the interim successor to generic const expressions. Essentially, const item RHS's will be allowed to do arbitrary const operations using generics. The limitation is that these const items will be treated opaquely, like ADTs in nominal typing, such that uses of them will only be equal if the same const item is referenced. In other words, two const items with the exact same RHS will not be considered equal. I also added some logic to check feature gates that depend on others being enabled (like oGCA depending on mGCA). = Coherence = During coherence, OGCA consts should be normalized ambiguously because they are opaque but eventually resolved to a real value. We don't want two OGCAs that have the same value to be treated as distinct for coherence purposes. (Just like opaque types.) This actually doesn't work yet because there are pre-existing fundamental issues with equate relations involving consts that need to be normalized. The problem is that we normalize only one layer of the const item and don't actually process the resulting anon const. Normally the created inference variable should be handled, which in this case would cause us to hit the anon const, but that's not happening. Specifically, `visit_const` on `Generalizer` should be updated to be similar to `visit_ty`. --- compiler/rustc_ast_passes/src/errors.rs | 10 +++ compiler/rustc_ast_passes/src/feature_gate.rs | 22 +++++++ compiler/rustc_ast_passes/src/lib.rs | 1 + compiler/rustc_feature/src/lib.rs | 3 +- compiler/rustc_feature/src/unstable.rs | 8 +++ compiler/rustc_hir_analysis/src/collect.rs | 64 ++++++++++++++++++- .../src/collect/generics_of.rs | 2 + .../src/hir_ty_lowering/mod.rs | 5 ++ compiler/rustc_middle/src/ty/consts.rs | 15 +---- compiler/rustc_middle/src/ty/context.rs | 3 + compiler/rustc_middle/src/ty/mod.rs | 4 +- .../src/solve/normalizes_to/anon_const.rs | 15 ++++- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_span/src/symbol.rs | 1 + .../rustc_trait_selection/src/traits/mod.rs | 14 ++++ compiler/rustc_type_ir/src/const_kind.rs | 20 ++++++ compiler/rustc_type_ir/src/interner.rs | 1 + .../non_valtreeable_const_arg-2.rs | 2 +- .../non_valtreeable_const_arg-2.stderr | 6 +- .../associated-const-bindings/ambiguity.rs | 2 +- .../coexisting-with-type-binding.rs | 2 +- ...dyn-compat-assoc-const-ty-mentions-self.rs | 1 + ...compat-assoc-const-ty-mentions-self.stderr | 4 +- ...elf-const-projections-in-assoc-const-ty.rs | 13 +++- ...const-projections-in-assoc-const-ty.stderr | 8 +-- .../esc-bound-var-in-ty.rs | 1 + .../esc-bound-var-in-ty.stderr | 2 +- .../mgca/adt_expr_arg_simple.stderr | 2 + .../mgca/early-bound-param-lt-bad.stderr | 2 + .../mgca/explicit_anon_consts.stderr | 14 ++++ .../mgca/selftyalias-containing-param.stderr | 1 + .../ui/const-generics/mgca/selftyparam.stderr | 2 + .../size-of-generic-ptr-in-array-len.stderr | 2 + .../mgca/tuple_ctor_complex_args.stderr | 2 + .../mgca/tuple_expr_arg_complex.stderr | 2 + .../mgca/type_const-on-generic-expr.stderr | 4 ++ .../mgca/type_const-on-generic_expr-2.stderr | 6 ++ .../unbraced_const_block_const_arg_gated.rs | 1 - ...nbraced_const_block_const_arg_gated.stderr | 12 +--- tests/ui/const-generics/ogca/basic-fail.rs | 22 +++++++ .../ui/const-generics/ogca/basic-fail.stderr | 9 +++ tests/ui/const-generics/ogca/basic.rs | 22 +++++++ .../ogca/coherence-ambiguous.rs | 21 ++++++ .../const-generics/ogca/rhs-but-not-root.rs | 14 ++++ .../ogca/rhs-but-not-root.stderr | 8 +++ .../feature-gate-opaque-generic-const-args.rs | 9 +++ ...ture-gate-opaque-generic-const-args.stderr | 10 +++ .../assoc-const-no-infer-ice-115806.rs | 2 +- 48 files changed, 347 insertions(+), 53 deletions(-) create mode 100644 tests/ui/const-generics/ogca/basic-fail.rs create mode 100644 tests/ui/const-generics/ogca/basic-fail.stderr create mode 100644 tests/ui/const-generics/ogca/basic.rs create mode 100644 tests/ui/const-generics/ogca/coherence-ambiguous.rs create mode 100644 tests/ui/const-generics/ogca/rhs-but-not-root.rs create mode 100644 tests/ui/const-generics/ogca/rhs-but-not-root.stderr create mode 100644 tests/ui/feature-gates/feature-gate-opaque-generic-const-args.rs create mode 100644 tests/ui/feature-gates/feature-gate-opaque-generic-const-args.stderr diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index baf6f6beaeed7..7282a5168213c 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -950,6 +950,16 @@ pub(crate) struct IncompatibleFeatures { pub f2: Symbol, } +#[derive(Diagnostic)] +#[diag("`{$parent}` requires {$missing} to be enabled")] +#[help("enable all of these features")] +pub(crate) struct MissingDependentFeatures { + #[primary_span] + pub parent_span: Span, + pub parent: Symbol, + pub missing: String, +} + #[derive(Diagnostic)] #[diag("negative bounds are not supported")] pub(crate) struct NegativeBoundUnsupported { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1b1bbb1564c46..ce9001d659318 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -441,6 +441,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { maybe_stage_features(sess, features, krate); check_incompatible_features(sess, features); + check_dependent_features(sess, features); check_new_solver_banned_features(sess, features); let mut visitor = PostExpansionVisitor { sess, features }; @@ -649,6 +650,27 @@ fn check_incompatible_features(sess: &Session, features: &Features) { } } +fn check_dependent_features(sess: &Session, features: &Features) { + for &(parent, children) in + rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent)) + { + if children.iter().any(|f| !features.enabled(*f)) { + let parent_span = features + .enabled_features_iter_stable_order() + .find_map(|(name, span)| (name == parent).then_some(span)) + .unwrap(); + // FIXME: should probably format this in fluent instead of here + let missing = children + .iter() + .filter(|f| !features.enabled(**f)) + .map(|s| format!("`{}`", s.as_str())) + .intersperse(String::from(", ")) + .collect(); + sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing }); + } + } +} + fn check_new_solver_banned_features(sess: &Session, features: &Features) { if !sess.opts.unstable_opts.next_solver.globally { return; diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 2630348c49c1f..7793f786cefee 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -5,6 +5,7 @@ // tidy-alphabetical-start #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(iter_is_partitioned)] // tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 4ba50d03d707b..619726f0d5d8f 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -136,5 +136,6 @@ pub use builtin_attrs::{ }; pub use removed::REMOVED_LANG_FEATURES; pub use unstable::{ - EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES, + DEPENDENT_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, + UNSTABLE_LANG_FEATURES, }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2ab7714f22ca9..a941eb1f459ed 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -605,6 +605,8 @@ declare_features! ( (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using fields with slice type in offset_of! (unstable, offset_of_slice, "1.81.0", Some(126151)), + /// Allows using generics in more complex const expressions, based on definitional equality. + (unstable, opaque_generic_const_args, "CURRENT_RUSTC_VERSION", Some(151972)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows specifying nop padding on functions for dynamic patching. @@ -782,3 +784,9 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[ // boolean logic required to tell which typing rules to use. (sym::ref_pat_eat_one_layer_2024, sym::ref_pat_eat_one_layer_2024_structural), ]; + +/// Some features require one or more other features to be enabled. +pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[ + (sym::opaque_generic_const_args, &[sym::min_generic_const_args]), + (sym::unsized_const_params, &[sym::adt_const_params]), +]; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f50aff187f252..f3086266eec00 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -16,7 +16,7 @@ use std::cell::Cell; use std::iter; -use std::ops::Bound; +use std::ops::{Bound, ControlFlow}; use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; @@ -26,12 +26,13 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err, }; use rustc_hir::attrs::AttributeKind; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt}; +use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind, find_attr}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; +use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{ @@ -1511,6 +1512,20 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id)); if tcx.features().generic_const_exprs() { ty::AnonConstKind::GCE + } else if tcx.features().opaque_generic_const_args() { + // Only anon consts that are the RHS of a const item can be OGCA. + // Note: We can't just check tcx.parent because it needs to be EXACTLY + // the RHS, not just part of the RHS. + if !is_anon_const_rhs_of_const_item(tcx, def) { + return ty::AnonConstKind::MCG; + } + + let body = tcx.hir_body_owned_by(def); + let mut visitor = OGCAParamVisitor(tcx); + match visitor.visit_body(body) { + ControlFlow::Break(UsesParam) => ty::AnonConstKind::OGCA, + ControlFlow::Continue(()) => ty::AnonConstKind::MCG, + } } else if tcx.features().min_generic_const_args() { ty::AnonConstKind::MCG } else if let hir::Node::Expr(hir::Expr { @@ -1528,6 +1543,49 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin } } +fn is_anon_const_rhs_of_const_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + let hir_id = tcx.local_def_id_to_hir_id(def_id); + let Some((_, grandparent_node)) = tcx.hir_parent_iter(hir_id).nth(1) else { return false }; + let (Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, _, ct_rhs), .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(_, ct_rhs), .. }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(_, Some(ct_rhs)), .. + })) = grandparent_node + else { + return false; + }; + let hir::ConstItemRhs::TypeConst(hir::ConstArg { + kind: hir::ConstArgKind::Anon(rhs_anon), .. + }) = ct_rhs + else { + return false; + }; + def_id == rhs_anon.def_id +} + +struct OGCAParamVisitor<'tcx>(TyCtxt<'tcx>); + +struct UsesParam; + +impl<'tcx> Visitor<'tcx> for OGCAParamVisitor<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + type Result = ControlFlow; + + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { + self.0 + } + + fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: HirId) -> ControlFlow { + if let Res::Def(DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, _) = + path.res + { + return ControlFlow::Break(UsesParam); + } + + intravisit::walk_path(self, path) + } +} + #[instrument(level = "debug", skip(tcx), ret)] fn const_of_item<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 511d513216eb2..0723418d8ddfe 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -92,6 +92,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { match tcx.anon_const_kind(def_id) { // Stable: anon consts are not able to use any generic parameters... ty::AnonConstKind::MCG => None, + // OGCA anon consts inherit their parent's generics. + ty::AnonConstKind::OGCA => Some(parent_did), // we provide generics to repeat expr counts as a backwards compatibility hack. #76200 ty::AnonConstKind::RepeatExprCount => Some(parent_did), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a79170452fae8..7a03d8b220c5c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -404,6 +404,11 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> { diag.span_note(impl_.self_ty.span, "not a concrete type"); } } + if self.tcx.features().min_generic_const_args() + && !self.tcx.features().opaque_generic_const_args() + { + diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items"); + } diag.emit() } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5581ad5669aa9..3e17943a88574 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::HashStable; use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; @@ -335,16 +335,3 @@ impl<'tcx> Const<'tcx> { TypeWalker::new(self.into()) } } - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)] -pub enum AnonConstKind { - /// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope - GCE, - /// stable `min_const_generics` anon consts are not allowed to use any generic parameters - MCG, - /// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters - /// but must not depend on the actual instantiation. See #76200 for more information - RepeatExprCount, - /// anon consts outside of the type system, e.g. enum discriminants - NonTypeSystem, -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e43a30091f507..1bb83530487df 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -238,6 +238,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { self.const_of_item(def_id) } + fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind { + self.anon_const_kind(def_id) + } type AdtDef = ty::AdtDef<'tcx>; fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0220531b09fa8..37871aad4a775 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -76,8 +76,8 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, - ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, + AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, ExprKind, ScalarInt, + SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 46312be5ea9a9..eb6a1b51421ca 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -1,4 +1,4 @@ -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, TypingMode}; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -14,7 +14,18 @@ where &mut self, goal: Goal>, ) -> QueryResult { - if let Some(normalized_const) = self.evaluate_const( + if self.typing_mode() == TypingMode::Coherence + && self.cx().anon_const_kind(goal.predicate.alias.def_id) == ty::AnonConstKind::OGCA + { + // During coherence, OGCA consts should be normalized ambiguously + // because they are opaque but eventually resolved to a real value. + // We don't want two OGCAs that have the same value to be treated + // as distinct for coherence purposes. (Just like opaque types.) + // + // We can't rely on evaluate_const below because that particular wrapper + // treats too-generic consts as a successful evaluation. + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } else if let Some(normalized_const) = self.evaluate_const( goal.param_env, ty::UnevaluatedConst::new( goal.predicate.alias.def_id.try_into().unwrap(), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c35ddc4dc9438..9ac9bd5c0e466 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1551,7 +1551,9 @@ impl<'a> Parser<'a> { let rhs = if self.eat(exp!(Eq)) { if attr::contains_name(attrs, sym::type_const) { - Some(ConstItemRhs::TypeConst(self.parse_const_arg()?)) + let ct = + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?; + Some(ConstItemRhs::TypeConst(ct)) } else { Some(ConstItemRhs::Body(self.parse_expr()?)) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1915ff0380fda..6aa2eae556e25 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1628,6 +1628,7 @@ symbols! { on_const, on_unimplemented, opaque, + opaque_generic_const_args, opaque_module_name_placeholder: "", open_options_new, ops, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4e027a301cc8b..08f1d947dfb5c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -681,6 +681,20 @@ pub fn try_evaluate_const<'tcx>( (args, typing_env) } + Some(ty::AnonConstKind::OGCA) => { + if infcx.typing_mode() != TypingMode::PostAnalysis { + // OGCA anon consts should be treated as always having generics + // during anything before codegen (or maybe MIR opts too). + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + + let typing_env = ty::TypingEnv::fully_monomorphized(); + (uv.args, typing_env) + } Some(ty::AnonConstKind::MCG) | Some(ty::AnonConstKind::NonTypeSystem) | None => { // We are only dealing with "truly" generic/uninferred constants here: // - GCEConsts have been handled separately diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index b215230ea443c..1c39f31469b1c 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -200,3 +200,23 @@ impl ValTreeKind { } } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub enum AnonConstKind { + /// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope + GCE, + /// stable `min_const_generics` anon consts are not allowed to use any generic parameters + MCG, + /// `feature(opaque_generic_const_args)` anon consts are allowed to use arbitrary + /// generic parameters in scope, but only if they syntactically reference them. + OGCA, + /// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters + /// but must not depend on the actual instantiation. See #76200 for more information + RepeatExprCount, + /// anon consts outside of the type system, e.g. enum discriminants + NonTypeSystem, +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 59ae6733fb847..8f446cdfba6d5 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -205,6 +205,7 @@ pub trait Interner: fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; + fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; type AdtDef: AdtDef; fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef; diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs index 6b87ad86d4bc2..e364368b8a4cf 100644 --- a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs @@ -1,4 +1,4 @@ -#![feature(generic_const_exprs, unsized_const_params)] +#![feature(adt_const_params, generic_const_exprs, unsized_const_params)] #![allow(incomplete_features)] // Regression test for 128232 diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr index 72dfda50ea5ca..b13f76eabadbc 100644 --- a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr @@ -9,13 +9,11 @@ help: you might be missing a const parameter LL | impl Wrapper<{ bar() }> { | +++++++++++++++++++++++ -error: using function pointers as const generic parameters is forbidden +error[E0741]: using function pointers as const generic parameters is forbidden --> $DIR/non_valtreeable_const_arg-2.rs:8:25 | LL | struct Wrapper; | ^^^^ - | - = note: the only supported types are integers, `bool`, and `char` error[E0599]: the function or associated item `call` exists for struct `Wrapper`, but its trait bounds were not satisfied --> $DIR/non_valtreeable_const_arg-2.rs:17:26 @@ -37,5 +35,5 @@ note: the trait `Fn` must be implemented error: aborting due to 3 previous errors -Some errors have detailed explanations: E0425, E0599. +Some errors have detailed explanations: E0425, E0599, E0741. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/associated-const-bindings/ambiguity.rs b/tests/ui/const-generics/associated-const-bindings/ambiguity.rs index 6bc2a6d5d1533..785d43e51b3d8 100644 --- a/tests/ui/const-generics/associated-const-bindings/ambiguity.rs +++ b/tests/ui/const-generics/associated-const-bindings/ambiguity.rs @@ -1,7 +1,7 @@ // We used to say "ambiguous associated type" on ambiguous associated consts. // Ensure that we now use the correct label. -#![feature(min_generic_const_args, unsized_const_params)] +#![feature(adt_const_params, min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait0: Parent0 + Parent0 {} diff --git a/tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs b/tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs index 0042159867113..0af91bfe7da80 100644 --- a/tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs +++ b/tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs @@ -5,7 +5,7 @@ //@ check-pass -#![feature(min_generic_const_args, unsized_const_params)] +#![feature(adt_const_params, min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait: SuperTrait { diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs index d19e7acbaff0d..bd26acce681fc 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs @@ -3,6 +3,7 @@ //@ dont-require-annotations: NOTE +#![feature(adt_const_params)] #![feature(generic_const_items)] #![feature(generic_const_parameter_types)] #![feature(min_generic_const_args)] diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr index dba1643d2c5c6..dedbdd7f82bbb 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr @@ -1,12 +1,12 @@ error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:37:16 + --> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:38:16 | LL | let _: dyn Trait; | ^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:17:11 + --> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:18:11 | LL | trait Trait { | ----- this trait is not dyn compatible... diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs index 936556e957cad..fc3bd1d2e753f 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs @@ -4,17 +4,24 @@ // to the rest of the compiler and by extension the user via diagnostics. //@ known-bug: unknown -#![feature(min_generic_const_args, unsized_const_params, generic_const_parameter_types)] +#![feature( + adt_const_params, + min_generic_const_args, + unsized_const_params, + generic_const_parameter_types +)] #![expect(incomplete_features)] trait A { type Ty: std::marker::ConstParamTy_; - #[type_const] const CT: Self::Ty; + #[type_const] + const CT: Self::Ty; } impl A for () { type Ty = i32; - #[type_const] const CT: i32 = 0; + #[type_const] + const CT: i32 = 0; } fn main() { diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr index 8ee231ec070fd..0b8dae1aac43a 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr @@ -1,23 +1,23 @@ error[E0277]: the trait bound `FreshTy(0): A` is not satisfied - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:27:33 + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:34:33 | LL | let _: dyn A; | ^ the trait `A` is not implemented for `FreshTy(0)` | help: the trait `A` is implemented for `()` - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:15:1 + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:21:1 | LL | impl A for () { | ^^^^^^^^^^^^^ error[E0277]: the trait bound `FreshTy(0): A` is not satisfied - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:29:34 + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:36:34 | LL | let _: &dyn A = &(); | ^ the trait `A` is not implemented for `FreshTy(0)` | help: the trait `A` is implemented for `()` - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:15:1 + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:21:1 | LL | impl A for () { | ^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs index d32737fcb62f5..4d06cdc7620f4 100644 --- a/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs +++ b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs @@ -1,6 +1,7 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. #![feature( + adt_const_params, min_generic_const_args, unsized_const_params, generic_const_parameter_types, diff --git a/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr index 122893662933d..3966483aa6002 100644 --- a/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr +++ b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/esc-bound-var-in-ty.rs:15:35 + --> $DIR/esc-bound-var-in-ty.rs:16:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr index 8b9c228c1ee53..f1d5e5c674756 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr @@ -9,6 +9,8 @@ error: generic parameters may not be used in const operations | LL | foo::<{ Some:: { 0: const { N + 1 } } }>(); | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr index 461a26e33a3ce..e0804158952d1 100644 --- a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr @@ -3,6 +3,8 @@ error: generic parameters may not be used in const operations | LL | T: Trait | ^^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index 551815c4c31a0..1251f4415171d 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -39,42 +39,56 @@ error: generic parameters may not be used in const operations | LL | const ITEM3: usize = const { N }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:60:31 | LL | T3: Trait, | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:69:58 | LL | struct Default3; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:28:27 | LL | let _3 = [(); const { N }]; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:33:26 | LL | let _6: [(); const { N }] = todo!(); | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:11:41 | LL | type Adt3 = Foo; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:19:42 | LL | type Arr3 = [(); const { N }]; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 13 previous errors diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr index fdd3e6efdf653..1c841e39e6739 100644 --- a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr @@ -9,6 +9,7 @@ note: not a concrete type | LL | impl S { | ^^^^ + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/selftyparam.stderr b/tests/ui/const-generics/mgca/selftyparam.stderr index 376e63da9a759..c3e0770fb978e 100644 --- a/tests/ui/const-generics/mgca/selftyparam.stderr +++ b/tests/ui/const-generics/mgca/selftyparam.stderr @@ -3,6 +3,8 @@ error: generic parameters may not be used in const operations | LL | fn foo() -> [(); const { let _: Self; 1 }]; | ^^^^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr index 913d8195fe21d..6d8d3b4054d34 100644 --- a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr @@ -9,6 +9,8 @@ error: generic parameters may not be used in const operations | LL | [0; const { size_of::<*mut T>() }]; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr index e0ea3fd5560c8..2961c714d1415 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr @@ -9,6 +9,8 @@ error: generic parameters may not be used in const operations | LL | with_point::<{ Point(const { N + 1 }, N) }>(); | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr index b294e1032ce8f..b4853d3c2e38c 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr @@ -21,6 +21,8 @@ error: generic parameters may not be used in const operations | LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index f339e82beeeda..8d43f2177562f 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -3,12 +3,16 @@ error: generic parameters may not be used in const operations | LL | const FREE1: usize = const { std::mem::size_of::() }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic-expr.rs:8:46 | LL | const FREE2: usize = const { I + 1 }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr index 9d4e99ca0aaf3..1a6097752e335 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr @@ -3,18 +3,24 @@ error: generic parameters may not be used in const operations | LL | const N1: usize = const { std::mem::size_of::() }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic_expr-2.rs:20:47 | LL | const N2: usize = const { I + 1 }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic_expr-2.rs:23:35 | LL | const N3: usize = const { 2 & X }; | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs index 588fa2f913b63..c01fb47002b24 100644 --- a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs @@ -35,7 +35,6 @@ const NON_TYPE_CONST: usize = const { 1 }; #[type_const] //~^ ERROR: the `#[type_const]` attribute is an experimental feature const TYPE_CONST: usize = const { 1 }; -//~^ ERROR: unbraced const blocks as const args are experimental static STATIC: usize = const { 1 }; diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr index 00db630c27e9e..bbcd9f9897a63 100644 --- a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr @@ -48,16 +48,6 @@ LL | generic::(); = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:37:27 - | -LL | const TYPE_CONST: usize = const { 1 }; - | ^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the `#[type_const]` attribute is an experimental feature --> $DIR/unbraced_const_block_const_arg_gated.rs:35:1 | @@ -68,6 +58,6 @@ LL | #[type_const] = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/ogca/basic-fail.rs b/tests/ui/const-generics/ogca/basic-fail.rs new file mode 100644 index 0000000000000..87176c7b067e6 --- /dev/null +++ b/tests/ui/const-generics/ogca/basic-fail.rs @@ -0,0 +1,22 @@ +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(opaque_generic_const_args)] +#![expect(incomplete_features)] + +#[type_const] +const ADD1: usize = const { N + 1 }; + +#[type_const] +const INC: usize = const { N + 1 }; + +#[type_const] +const ONE: usize = ADD1::<0>; + +#[type_const] +const OTHER_ONE: usize = INC::<0>; + +// Not definitionally equal. +const ARR: [(); ADD1::<0>] = [(); INC::<0>]; +//~^ ERROR mismatched types + +fn main() {} diff --git a/tests/ui/const-generics/ogca/basic-fail.stderr b/tests/ui/const-generics/ogca/basic-fail.stderr new file mode 100644 index 0000000000000..05de01b132c6f --- /dev/null +++ b/tests/ui/const-generics/ogca/basic-fail.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/basic-fail.rs:19:30 + | +LL | const ARR: [(); ADD1::<0>] = [(); INC::<0>]; + | ^^^^^^^^^^^^^^ expected an array with a size of const { N + 1 }, found one with a size of const { N + 1 } + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/ogca/basic.rs b/tests/ui/const-generics/ogca/basic.rs new file mode 100644 index 0000000000000..c8aec9ee24ce2 --- /dev/null +++ b/tests/ui/const-generics/ogca/basic.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(opaque_generic_const_args)] +#![expect(incomplete_features)] + +#[type_const] +const ADD1: usize = const { N + 1 }; + +#[type_const] +const INC: usize = ADD1::; + +#[type_const] +const ONE: usize = ADD1::<0>; + +#[type_const] +const OTHER_ONE: usize = INC::<0>; + +const ARR: [(); ADD1::<0>] = [(); INC::<0>]; + +fn main() {} diff --git a/tests/ui/const-generics/ogca/coherence-ambiguous.rs b/tests/ui/const-generics/ogca/coherence-ambiguous.rs new file mode 100644 index 0000000000000..c8c088b1e8fc3 --- /dev/null +++ b/tests/ui/const-generics/ogca/coherence-ambiguous.rs @@ -0,0 +1,21 @@ +// FIXME(ogca): this should ERROR not pass!! +//@ check-pass + +#![feature(generic_const_items, min_generic_const_args, opaque_generic_const_args)] +#![expect(incomplete_features)] + +#[type_const] +const FOO: usize = const { N + 1 }; + +#[type_const] +const BAR: usize = const { N + 1 }; + +trait Trait {} + +impl Trait for [(); FOO::<1>] {} +impl Trait for [(); BAR::<1>] {} +// FIXME(ogca): this should ERROR! +impl Trait for [(); BAR::<2>] {} +// FIXME(ogca): this should ERROR! + +fn main() {} diff --git a/tests/ui/const-generics/ogca/rhs-but-not-root.rs b/tests/ui/const-generics/ogca/rhs-but-not-root.rs new file mode 100644 index 0000000000000..4ed136f04ced3 --- /dev/null +++ b/tests/ui/const-generics/ogca/rhs-but-not-root.rs @@ -0,0 +1,14 @@ +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(opaque_generic_const_args)] +#![expect(incomplete_features)] + +// Anon consts must be the root of the RHS to be OGCA. +#[type_const] +const FOO: usize = ID::; +//~^ ERROR generic parameters may not be used in const operations + +#[type_const] +const ID: usize = N; + +fn main() {} diff --git a/tests/ui/const-generics/ogca/rhs-but-not-root.stderr b/tests/ui/const-generics/ogca/rhs-but-not-root.stderr new file mode 100644 index 0000000000000..f4fdf5fb981b7 --- /dev/null +++ b/tests/ui/const-generics/ogca/rhs-but-not-root.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/rhs-but-not-root.rs:8:49 + | +LL | const FOO: usize = ID::; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.rs b/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.rs new file mode 100644 index 0000000000000..0b78911158ba2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.rs @@ -0,0 +1,9 @@ +#![feature(generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] + +#[type_const] +const INC: usize = const { N + 1 }; +//~^ ERROR generic parameters may not be used in const operations +//~| HELP add `#![feature(opaque_generic_const_args)]` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.stderr b/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.stderr new file mode 100644 index 0000000000000..1b87443aa3cba --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-opaque-generic-const-args.stderr @@ -0,0 +1,10 @@ +error: generic parameters may not be used in const operations + --> $DIR/feature-gate-opaque-generic-const-args.rs:5:44 + | +LL | const INC: usize = const { N + 1 }; + | ^ + | + = help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items + +error: aborting due to 1 previous error + diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index fb2506daf078d..518ed64523691 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -1,6 +1,6 @@ // ICE: assertion failed: !value.has_infer() // issue: rust-lang/rust#115806 -#![feature(min_generic_const_args, unsized_const_params)] +#![feature(adt_const_params, min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] pub struct NoPin; From f1b4c2a0e64ccb5c1b4b2b2391ac91f40d143302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 7 Feb 2026 14:42:17 +0100 Subject: [PATCH 3/5] Port rustc_insignificant_dtor to the new attribute parser --- .../src/attributes/rustc_internal.rs | 13 +++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_ty_utils/src/needs_drop.rs | 6 +++--- 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index a8a0ee3e5e225..4740cc107353b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -739,6 +739,19 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser { } } +pub(crate) struct RustcInsignificantDtorParser; + +impl NoArgsAttributeParser for RustcInsignificantDtorParser { + const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::ForeignTy), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInsignificantDtor; +} + pub(crate) struct RustcEffectiveVisibilityParser; impl NoArgsAttributeParser for RustcEffectiveVisibilityParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ad39b0ec26d93..7921928ce7c51 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -270,6 +270,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 79452913c2594..aaeebcc5c66db 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1120,6 +1120,9 @@ pub enum AttributeKind { /// Represents `#[rustc_if_this_changed]` RustcIfThisChanged(Span, Option), + /// Represents `#[rustc_insignificant_dtor]` + RustcInsignificantDtor, + /// Represents `#[rustc_intrinsic]` RustcIntrinsic, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index ba351d80544c6..4fb20599a026d 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -118,6 +118,7 @@ impl AttributeKind { RustcHasIncoherentInherentImpls => Yes, RustcHiddenTypeOfOpaques => No, RustcIfThisChanged(..) => No, + RustcInsignificantDtor => Yes, RustcIntrinsic => Yes, RustcIntrinsicConstStableIndirect => No, RustcLayout(..) => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6c4b76a08ad27..2f1695f0712a5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -313,6 +313,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::RustcHiddenTypeOfOpaques | AttributeKind::RustcIfThisChanged(..) + | AttributeKind::RustcInsignificantDtor | AttributeKind::RustcIntrinsic | AttributeKind::RustcIntrinsicConstStableIndirect | AttributeKind::RustcLayout(..) @@ -386,7 +387,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::default_lib_allocator | sym::rustc_diagnostic_item | sym::rustc_no_mir_inline - | sym::rustc_insignificant_dtor | sym::rustc_nonnull_optimization_guaranteed | sym::rustc_inherit_overflow_checks | sym::rustc_trivial_field_reads diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 0ef435b1a0e21..06eef7e95145e 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -1,13 +1,14 @@ //! Check whether a type has (potentially) non-trivial drop glue. use rustc_data_structures::fx::FxHashSet; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::DefId; +use rustc_hir::find_attr; use rustc_hir::limit::Limit; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components}; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; -use rustc_span::sym; use tracing::{debug, instrument}; use crate::errors::NeedsDropOverflow; @@ -396,8 +397,7 @@ fn adt_consider_insignificant_dtor<'tcx>( tcx: TyCtxt<'tcx>, ) -> impl Fn(ty::AdtDef<'tcx>) -> Option { move |adt_def: ty::AdtDef<'tcx>| { - let is_marked_insig = tcx.has_attr(adt_def.did(), sym::rustc_insignificant_dtor); - if is_marked_insig { + if find_attr!(tcx.get_all_attrs(adt_def.did()), AttributeKind::RustcInsignificantDtor) { // In some cases like `std::collections::HashMap` where the struct is a wrapper around // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies // outside stdlib, we might choose to still annotate the wrapper (std HashMap) with From 9d6e120939cad8e87c3ccd4e2f33d3591b82edf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 7 Feb 2026 15:06:32 +0100 Subject: [PATCH 4/5] remove from impl block in std --- library/alloc/src/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index d6dcba7107a9c..fba967c04895a 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -103,6 +103,7 @@ use crate::vec::Vec; /// and other memory errors. #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] #[rustc_diagnostic_item = "cstring_type"] +#[rustc_insignificant_dtor] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct CString { // Invariant 1: the slice ends with a zero byte and has a length of at least one. @@ -694,7 +695,6 @@ impl CString { // memory-unsafe code from working by accident. Inline // to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] -#[rustc_insignificant_dtor] impl Drop for CString { #[inline] fn drop(&mut self) { From 2dda303229b936641c29db1f277a9940473ebc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 5 Feb 2026 15:12:05 +0100 Subject: [PATCH 5/5] Port rustc_strict_coherence to the new attribute parser --- .../src/attributes/rustc_internal.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + .../rustc_hir/src/attrs/data_structures.rs | 4 ++++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_middle/src/error.rs | 2 +- .../src/traits/specialization_graph.rs | 19 ++++++------------- compiler/rustc_passes/src/check_attr.rs | 2 +- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index a8a0ee3e5e225..c4c0a04c44e4a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -845,3 +845,18 @@ impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectPar const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect; } + +pub(crate) struct RustcStrictCoherenceParser; + +impl NoArgsAttributeParser for RustcStrictCoherenceParser { + const PATH: &[Symbol] = &[sym::rustc_strict_coherence]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::ForeignTy), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStrictCoherence; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ad39b0ec26d93..16a3403b5243f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -286,6 +286,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 79452913c2594..de7b2bd065466 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1230,6 +1230,9 @@ pub enum AttributeKind { /// Represents `#[rustc_std_internal_symbol]`. RustcStdInternalSymbol(Span), + /// Represents `#[rustc_strict_coherence]`. + RustcStrictCoherence(Span), + /// Represents `#[rustc_symbol_name]` RustcSymbolName(Span), @@ -1266,6 +1269,7 @@ pub enum AttributeKind { /// Span of the attribute. span: Span, }, + /// Represents `#[target_feature(enable = "...")]` and /// `#[unsafe(force_target_feature(enable = "...")]`. TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index ba351d80544c6..954c72ca86fe3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -153,6 +153,7 @@ impl AttributeKind { RustcSkipDuringMethodDispatch { .. } => No, RustcSpecializationTrait(..) => No, RustcStdInternalSymbol(..) => No, + RustcStrictCoherence(..) => Yes, RustcSymbolName(..) => Yes, RustcThenThisWouldNeed(..) => No, RustcUnsafeSpecializationMarker(..) => No, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index a5d5978916eb9..d487caf4d3ac9 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -93,7 +93,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { #[primary_span] pub span: Span, #[label("due to this attribute")] - pub attr_span: Option, + pub attr_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 05c19db4caa8c..84415a592a2ec 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -1,8 +1,9 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{DefId, DefIdMap}; +use rustc_hir::find_attr; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_span::sym; use crate::error::StrictCoherenceNeedsNegativeCoherence; use crate::ty::fast_reject::SimplifiedType; @@ -61,23 +62,15 @@ pub enum OverlapMode { impl OverlapMode { pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode { let with_negative_coherence = tcx.features().with_negative_coherence(); - let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence); + let strict_coherence = find_attr!(tcx.get_all_attrs(trait_id), AttributeKind::RustcStrictCoherence(span) => *span); if with_negative_coherence { - if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative } + if strict_coherence.is_some() { OverlapMode::Strict } else { OverlapMode::WithNegative } } else { - if strict_coherence { - let attr_span = trait_id - .as_local() - .into_iter() - .flat_map(|local_def_id| { - tcx.hir_attrs(tcx.local_def_id_to_hir_id(local_def_id)) - }) - .find(|attr| attr.has_name(sym::rustc_strict_coherence)) - .map(|attr| attr.span()); + if let Some(span) = strict_coherence { tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence { span: tcx.def_span(trait_id), - attr_span, + attr_span: span, }); } OverlapMode::Stable diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6c4b76a08ad27..c29e4b2b1afec 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -344,6 +344,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcSkipDuringMethodDispatch { .. } | AttributeKind::RustcSpecializationTrait(..) | AttributeKind::RustcStdInternalSymbol (..) + | AttributeKind::RustcStrictCoherence(..) | AttributeKind::RustcSymbolName(..) | AttributeKind::RustcThenThisWouldNeed(..) | AttributeKind::RustcUnsafeSpecializationMarker(..) @@ -402,7 +403,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_never_type_options | sym::rustc_autodiff | sym::rustc_capture_analysis - | sym::rustc_strict_coherence | sym::rustc_mir | sym::rustc_outlives | sym::rustc_evaluate_where_clauses