Auto merge of #152373 - Zalathar:rollup-wDsfoHs, r=Zalathar

Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#150823 (Implement MVP for opaque generic const arguments)
 - rust-lang/rust#152071 (Implement stdio FD constants)
 - rust-lang/rust#152171 (Port `rustc_strict_coherence` to the new attribute parser)
 - rust-lang/rust#152291 (Port `rustc_insignificant_dtor`)

Failed merges:

 - rust-lang/rust#152180 (Port `rustc_reservation_impl` to the new attribute parser)
This commit is contained in:
bors 2026-02-09 05:59:48 +00:00
commit 4cd4c18438
59 changed files with 457 additions and 73 deletions

View file

@ -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 {

View file

@ -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;

View file

@ -5,6 +5,7 @@
// tidy-alphabetical-start
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
// tidy-alphabetical-end

View file

@ -739,6 +739,19 @@ impl<S: Stage> CombineAttributeParser<S> for RustcThenThisWouldNeedParser {
}
}
pub(crate) struct RustcInsignificantDtorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcInsignificantDtorParser {
const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
@ -845,3 +858,18 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectPar
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
}
pub(crate) struct RustcStrictCoherenceParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
const PATH: &[Symbol] = &[sym::rustc_strict_coherence];
const ON_DUPLICATE: OnDuplicate<S> = 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;
}

View file

@ -272,6 +272,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
Single<WithoutArgs<RustcInsignificantDtorParser>>,
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
Single<WithoutArgs<RustcIntrinsicParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
@ -289,6 +290,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcReallocatorParser>>,
Single<WithoutArgs<RustcRegionsParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<RustcStrictCoherenceParser>>,
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
Single<WithoutArgs<RustcVarianceParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,

View file

@ -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,
};

View file

@ -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]),
];

View file

@ -1126,6 +1126,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_if_this_changed]`
RustcIfThisChanged(Span, Option<Symbol>),
/// Represents `#[rustc_insignificant_dtor]`
RustcInsignificantDtor,
/// Represents `#[rustc_intrinsic]`
RustcIntrinsic,
@ -1239,6 +1242,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_std_internal_symbol]`.
RustcStdInternalSymbol(Span),
/// Represents `#[rustc_strict_coherence]`.
RustcStrictCoherence(Span),
/// Represents `#[rustc_symbol_name]`
RustcSymbolName(Span),
@ -1275,6 +1281,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 },

View file

@ -120,6 +120,7 @@ impl AttributeKind {
RustcHasIncoherentInherentImpls => Yes,
RustcHiddenTypeOfOpaques => No,
RustcIfThisChanged(..) => No,
RustcInsignificantDtor => Yes,
RustcIntrinsic => Yes,
RustcIntrinsicConstStableIndirect => No,
RustcLayout(..) => No,
@ -156,6 +157,7 @@ impl AttributeKind {
RustcSkipDuringMethodDispatch { .. } => No,
RustcSpecializationTrait(..) => No,
RustcStdInternalSymbol(..) => No,
RustcStrictCoherence(..) => Yes,
RustcSymbolName(..) => Yes,
RustcThenThisWouldNeed(..) => No,
RustcUnsafeSpecializationMarker(..) => No,

View file

@ -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<UsesParam>;
fn maybe_tcx(&mut self) -> TyCtxt<'tcx> {
self.0
}
fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: HirId) -> ControlFlow<UsesParam> {
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>,

View file

@ -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),

View file

@ -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()
}
}

View file

@ -93,7 +93,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
#[primary_span]
pub span: Span,
#[label("due to this attribute")]
pub attr_span: Option<Span>,
pub attr_span: Span,
}
#[derive(Diagnostic)]

View file

@ -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

View file

@ -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,
}

View file

@ -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 {

View file

@ -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,

View file

@ -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<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> {
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(),

View file

@ -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()?))
}

View file

@ -315,6 +315,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcHasIncoherentInherentImpls
| AttributeKind::RustcHiddenTypeOfOpaques
| AttributeKind::RustcIfThisChanged(..)
| AttributeKind::RustcInsignificantDtor
| AttributeKind::RustcIntrinsic
| AttributeKind::RustcIntrinsicConstStableIndirect
| AttributeKind::RustcLayout(..)
@ -347,6 +348,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcSkipDuringMethodDispatch { .. }
| AttributeKind::RustcSpecializationTrait(..)
| AttributeKind::RustcStdInternalSymbol (..)
| AttributeKind::RustcStrictCoherence(..)
| AttributeKind::RustcSymbolName(..)
| AttributeKind::RustcThenThisWouldNeed(..)
| AttributeKind::RustcUnsafeSpecializationMarker(..)
@ -389,7 +391,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
@ -405,7 +406,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_partition_reused
| sym::rustc_partition_codegened

View file

@ -1628,6 +1628,7 @@ symbols! {
on_const,
on_unimplemented,
opaque,
opaque_generic_const_args,
opaque_module_name_placeholder: "<opaque>",
open_options_new,
ops,

View file

@ -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

View file

@ -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<DtorType> {
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

View file

@ -200,3 +200,23 @@ impl<I: Interner> ValTreeKind<I> {
}
}
}
#[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,
}

View file

@ -205,6 +205,7 @@ pub trait Interner:
fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
-> ty::EarlyBinder<Self, Self::Ty>;
fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Const>;
fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind;
type AdtDef: AdtDef<Self>;
fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef;

View file

@ -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) {

View file

@ -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::*;

View file

@ -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) };

View file

@ -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

View file

@ -9,13 +9,11 @@ help: you might be missing a const parameter
LL | impl<const bar: /* Type */> 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<const F: fn()>;
| ^^^^
|
= note: the only supported types are integers, `bool`, and `char`
error[E0599]: the function or associated item `call` exists for struct `Wrapper<function>`, 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`.

View file

@ -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<i32> + Parent0<u32> {}

View file

@ -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 {

View file

@ -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)]

View file

@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $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...

View file

@ -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() {

View file

@ -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<Ty = i32, CT = 0>;
| ^ 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<Ty = i32, CT = 0> = &();
| ^ 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 () {
| ^^^^^^^^^^^^^

View file

@ -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,

View file

@ -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`

View file

@ -9,6 +9,8 @@ error: generic parameters may not be used in const operations
|
LL | foo::<{ Some::<u32> { 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

View file

@ -3,6 +3,8 @@ error: generic parameters may not be used in const operations
|
LL | T: Trait<const { let a: &'a (); 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

View file

@ -39,42 +39,56 @@ error: generic parameters may not be used in const operations
|
LL | const ITEM3<const N: usize>: 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<ASSOC = 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:69:58
|
LL | struct Default3<const N: usize, const M: 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: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<const N: usize> = Foo<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:19:42
|
LL | type Arr3<const N: usize> = [(); 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

View file

@ -9,6 +9,7 @@ note: not a concrete type
|
LL | impl<const N: usize> S<N> {
| ^^^^
= help: add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items
error: aborting due to 1 previous error

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -3,12 +3,16 @@ error: generic parameters may not be used in const operations
|
LL | const FREE1<T>: usize = const { std::mem::size_of::<T>() };
| ^
|
= 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<const I: usize>: 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

View file

@ -3,18 +3,24 @@ error: generic parameters may not be used in const operations
|
LL | const N1<T>: usize = const { std::mem::size_of::<T>() };
| ^
|
= 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<const I: usize>: 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

View file

@ -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 };

View file

@ -48,16 +48,6 @@ LL | generic::<const { 1 }>();
= 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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -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<const N: usize>: usize = const { N + 1 };
#[type_const]
const INC<const N: usize>: 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() {}

View file

@ -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`.

View file

@ -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<const N: usize>: usize = const { N + 1 };
#[type_const]
const INC<const N: usize>: usize = ADD1::<N>;
#[type_const]
const ONE: usize = ADD1::<0>;
#[type_const]
const OTHER_ONE: usize = INC::<0>;
const ARR: [(); ADD1::<0>] = [(); INC::<0>];
fn main() {}

View file

@ -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<const N: usize>: usize = const { N + 1 };
#[type_const]
const BAR<const N: usize>: 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() {}

View file

@ -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<const N: usize>: usize = ID::<const { N + 1 }>;
//~^ ERROR generic parameters may not be used in const operations
#[type_const]
const ID<const N: usize>: usize = N;
fn main() {}

View file

@ -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<const N: usize>: usize = ID::<const { N + 1 }>;
| ^
error: aborting due to 1 previous error

View file

@ -0,0 +1,9 @@
#![feature(generic_const_items, min_generic_const_args)]
#![expect(incomplete_features)]
#[type_const]
const INC<const N: usize>: usize = const { N + 1 };
//~^ ERROR generic parameters may not be used in const operations
//~| HELP add `#![feature(opaque_generic_const_args)]`
fn main() {}

View file

@ -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<const N: usize>: 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

View file

@ -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;