From 32aecb01255282a2c68d3edcf8cb848170b25ba8 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Tue, 11 Aug 2026 15:21:28 -0300 Subject: [PATCH 01/40] Represent live alias arguments as bitsets Store identity argument indices instead of bound generic arguments so callers can index concrete alias arguments without changing rigidness through instantiation. --- Cargo.lock | 1 + compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- .../rustc_metadata/src/rmeta/parameterized.rs | 1 + compiler/rustc_middle/src/queries.rs | 12 +- compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/traits/outlives_for_liveness.rs | 146 +++++++++--------- 6 files changed, 80 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60988e0ff4bc1..c71f76375cb52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4858,6 +4858,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_index", "rustc_infer", "rustc_macros", "rustc_middle", diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 3273013466245..990f134cafc24 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -482,8 +482,8 @@ define_tables! { anon_const_kind: Table>, const_of_item: Table>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, - live_args_for_alias_from_outlives_bounds: Table>>>>>, - args_known_to_outlive_alias_params: Table, Vec>)>>>>, + live_args_for_alias_from_outlives_bounds: Table>>>, + args_known_to_outlive_alias_params: Table)>>>, mut_restriction: Table>, } diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index 75b86f8dda274..346acceba7c1e 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -106,6 +106,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_index::bit_set::DenseBitSet, + rustc_index::bit_set::DenseBitSet, rustc_middle::metadata::AmbigModChild, rustc_middle::metadata::ModChild, rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index ca1cd2f45975f..96cd4f296c354 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2140,9 +2140,9 @@ rustc_queries! { desc { "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) } } - /// For an opaque type or trait associated type, return the list of potentially live - /// (identity) generic args from the set of outlives bounds on that alias. Callers should - /// instantiate the returned args with the concrete args of the alias. + /// For an opaque type or trait associated type, return the indices of potentially live + /// generic args from the set of outlives bounds on that alias. Callers should use the + /// indices with the concrete args of the alias. /// ```ignore (illustrative) /// // Edition 2024: all args are captured /// fn foo<'a, 'b, T: 'static>(&'a &'b T) -> impl Sized + 'a {} @@ -2155,16 +2155,16 @@ rustc_queries! { /// (and so is `T`, since `T: 'static` implies `T: 'a`) /// - `bar` outlives `'static`, so we know that no args are potentially live and we can return an empty set /// - `baz` has no outlives bound, so return `None` and let the caller decide what to do - query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx Option>>> { + query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx Option> { arena_cache desc { "identifying live args for alias `{:?}`", kind } } - /// For each region param of an alias, the identity args that are known to + /// For each region param of an alias, the indices of the identity args that are known to /// outlive it given only the alias's declared where-clauses. Used for liveness: /// these are the only args whose regions the underlying type of the alias /// could capture while satisfying an outlives bound on that param. - query args_known_to_outlive_alias_params(def_id: DefId) -> &'tcx ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec>)>> { + query args_known_to_outlive_alias_params(def_id: DefId) -> &'tcx Vec<(usize, rustc_index::bit_set::DenseBitSet)> { arena_cache desc { "computing the args known to outlive each region param of alias `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index ae231c217977d..4444a433f3579 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -11,6 +11,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs index 5cba32d742f62..f07cbde8a9f1a 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs @@ -1,6 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::ty::{ self, Flags, ImplTraitInTraitData, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, @@ -11,10 +12,10 @@ use crate::infer::outlives::test_type_match; use crate::infer::region_constraints::VerifyIfEq; use crate::regions::{region_known_to_outlive, ty_known_to_outlive}; -/// For a given alias type, this returns the set of (identity) generic args that +/// For a given alias type, this returns the set of indices into the identity generic args that /// are relevant for liveness, that can be inferred from outlives bounds on the /// alias itself, and the explicit and implicit outlives clauses of the alias. -/// Callers should instantiate the returned args with the concrete args of the alias. +/// Callers should use the indices with the concrete args of the alias. /// /// There are three cases to consider: /// 1. If there are *no* outlives bounds, then we return None. @@ -27,7 +28,7 @@ use crate::regions::{region_known_to_outlive, ty_known_to_outlive}; pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, kind: ty::AliasTyKind<'tcx>, -) -> Option>>> { +) -> Option> { let def_id = match kind { ty::AliasTyKind::Projection { def_id } | ty::AliasTyKind::Inherent { def_id } @@ -88,7 +89,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( // regions are going to be instantiated with free regions. if outlives_regions.contains(&tcx.lifetimes.re_static) { tracing::debug!("alias has a 'static outlives bound, so skipping visiting any regions"); - return Some(ty::EarlyBinder::bind(tcx, vec![])); + return Some(DenseBitSet::new_empty(self_identity_args.len())); } // Okay, so we know we have some outlives bounds, and that none of them are `'static`. @@ -96,37 +97,38 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( // an outlives-bound region. `args_known_to_outlive_alias_params` does this // for us, and in the case of opaques only includes *captured* regions, too. - let args_known_to_outlive = - tcx.args_known_to_outlive_alias_params(def_id).as_ref().skip_binder(); + let args_known_to_outlive = tcx.args_known_to_outlive_alias_params(def_id); tracing::debug!(?args_known_to_outlive); - let mut live_args: Option>> = None; + let mut live_args: Option> = None; for outlives_region in outlives_regions { - let Some(outlives_params) = - args_known_to_outlive.iter().find(|(r, _)| *r == outlives_region) + let Some(outlives_params) = args_known_to_outlive + .iter() + .find(|(idx, _)| self_identity_args[*idx].as_region() == Some(outlives_region)) else { continue; }; - let new_live_args = outlives_params.1.iter().copied().collect(); + let new_live_args = outlives_params.1.clone(); match &mut live_args { None => live_args = Some(new_live_args), - Some(prev) => *prev = prev.intersection(&new_live_args).copied().collect(), + Some(prev) => { + prev.intersect(&new_live_args); + } }; } - live_args.map(|c| ty::EarlyBinder::bind(tcx, c.into_iter().collect())) + live_args } -/// For each region param of this alias compute the identity args that are known -/// to outlive it, given only the alias's declared where-clauses. +/// For each region param of this alias compute the indices of the identity args +/// that are known to outlive it, given only the alias's declared where-clauses. /// /// Note: for opaques (including synthetic associated types from RPITITs), /// the outlives relationships are identified in the context of the *parent*, /// since bounds and well-formed types are not lowered. -// FIXME: this likely should return a `BitSet` instead of a `Vec>` #[tracing::instrument(level = "debug", skip(tcx), ret)] pub(crate) fn args_known_to_outlive_alias_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec>)>> { +) -> Vec<(usize, DenseBitSet)> { match tcx.def_kind(def_id) { DefKind::OpaqueTy => args_known_to_outlive_opaque_params(tcx, def_id), DefKind::AssocTy @@ -171,7 +173,7 @@ pub(crate) fn args_known_to_outlive_alias_params<'tcx>( pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec>)>> { +) -> Vec<(usize, DenseBitSet)> { let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let mut result = Vec::new(); @@ -207,7 +209,9 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( // build a `Region` from the opaque region's `LocalDefId`). let generics = tcx.generics_of(def_id); let mut parent_outlives_regions = Vec::with_capacity(generics.own_params.len()); - for opaque_arg in self_identity_args[generics.parent_count..].iter() { + for (opaque_arg_idx, opaque_arg) in + self_identity_args.iter().enumerate().skip(generics.parent_count) + { let Some(opaque_region) = opaque_arg.as_region() else { continue; }; @@ -218,7 +222,7 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( let parent_region = tcx.map_opaque_lifetime_to_parent_lifetime(region_def_id.expect_local()); tracing::debug!(?region_def_id, ?parent_region); - parent_outlives_regions.push((parent_region, opaque_region)); + parent_outlives_regions.push((parent_region, opaque_arg_idx)); } tracing::debug!(?parent_outlives_regions); @@ -227,9 +231,11 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( // 2) *Captured Regions* // // In both cases, we need to check known outlives for the *parent* region, because that's where the param_env and wf_tys are. - for (parent_outlived_region, opaque_outlived_region) in parent_outlives_regions.iter() { - let mut opaque_outlives_args = Vec::with_capacity(self_identity_args.len()); - for parent_outlives_arg in self_identity_args[..generics.parent_count].iter() { + for (parent_outlived_region, opaque_outlived_arg_idx) in parent_outlives_regions.iter() { + let mut opaque_outlives_args = DenseBitSet::new_empty(self_identity_args.len()); + for (parent_outlived_arg_idx, parent_outlives_arg) in + self_identity_args[..generics.parent_count].iter().enumerate() + { let type_outlives = match parent_outlives_arg.kind() { // Consts don't have any non-static regions ty::GenericArgKind::Const(_) => continue, @@ -249,10 +255,10 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( } // Types aren't captured, so don't need to map to the opaque - opaque_outlives_args.push(*parent_outlives_arg); + opaque_outlives_args.insert(parent_outlived_arg_idx); } - for &(parent_outlives_region, opaque_region) in parent_outlives_regions.iter() { + for &(parent_outlives_region, opaque_arg_idx) in parent_outlives_regions.iter() { let region_outlives = parent_outlives_region == *parent_outlived_region || region_known_to_outlive( tcx, @@ -266,32 +272,32 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( continue; } - opaque_outlives_args.push(opaque_region.into()); + opaque_outlives_args.insert(opaque_arg_idx); } - result.push((*opaque_outlived_region, opaque_outlives_args)); + result.push((*opaque_outlived_arg_idx, opaque_outlives_args)); } - ty::EarlyBinder::bind(tcx, result) + result } #[tracing::instrument(level = "debug", skip(tcx), ret)] pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec>)>> { +) -> Vec<(usize, DenseBitSet)> { let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let param_env = tcx.param_env(def_id); tracing::debug!(?param_env); let wf_tys = tcx.assumed_wf_types(def_id).iter().map(|(ty, _)| *ty).collect::>(); let mut result = Vec::new(); - for outlived_arg in self_identity_args.iter() { + for (outlived_arg_idx, outlived_arg) in self_identity_args.iter().enumerate() { let Some(outlived_region) = outlived_arg.as_region() else { continue; }; - let outliving_args = self_identity_args - .iter() - .filter(|arg| match arg.kind() { + let mut outliving_args = DenseBitSet::new_empty(self_identity_args.len()); + for (arg_idx, arg) in self_identity_args.iter().enumerate() { + let outlives = match arg.kind() { ty::GenericArgKind::Lifetime(r) => { region_known_to_outlive(tcx, def_id, param_env, &wf_tys, r, outlived_region) } @@ -299,16 +305,19 @@ pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( ty_known_to_outlive(tcx, def_id, param_env, &wf_tys, t, outlived_region) } ty::GenericArgKind::Const(_) => false, - }) - .collect(); - result.push((outlived_region, outliving_args)); + }; + if outlives { + outliving_args.insert(arg_idx); + } + } + result.push((outlived_arg_idx, outliving_args)); } - ty::EarlyBinder::bind(tcx, result) + result } /// For a param-env clause `for<'v..> ::Assoc<..>: 'bound` that -/// applies to `ty` (an alias with `alias_def_id`), returns the set of (identity) args -/// that the underlying type could possibly capture, as restricted by this clause. +/// applies to `ty` (an alias with `alias_def_id`), returns the set of indices into the +/// identity args that the underlying type could possibly capture, as restricted by this clause. /// /// As an example, let's imagine we had the following associated type definition: /// ```ignore (illustrative) @@ -345,7 +354,7 @@ fn live_args_for_outlives_clause<'tcx>( alias_def_id: DefId, ty: Ty<'tcx>, outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, -) -> Option>>> { +) -> Option> { // N.B. it's okay to skip the binder here (and in the rest of the function), // because all variables under binders do not escape let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) = @@ -380,7 +389,7 @@ fn live_args_for_outlives_clause<'tcx>( // // Of course, you may ask: "what if the function has a `'a: 'static` bound?" See the corresponding // comment in `live_args_for_alias_from_outlives_bounds` for why we don't need to worry about that. - ty::ReStatic => Some(FxIndexSet::default()), + ty::ReStatic => Some(DenseBitSet::new_empty(clause_identity_args.len())), ty::ReBound(_, br) => { // The bound is one of the clause's higher-ranked vars. Find the arg // positions it occupies, then (at the alias's identity level) find @@ -388,13 +397,15 @@ fn live_args_for_outlives_clause<'tcx>( // the alias's declared bounds -- only those can be captured by the // underlying type. let mut outlived_regions = Vec::new(); - for (clause_arg, identity_arg) in clause_args.iter().zip(clause_identity_args.iter()) { + for (clause_arg, (identity_arg_idx, _identity_arg)) in + clause_args.iter().zip(clause_identity_args.iter().enumerate()) + { match clause_arg.kind() { ty::GenericArgKind::Lifetime(r) => { if let ty::ReBound(_, arg_br) = r.kind() && arg_br.var == br.var { - outlived_regions.push(identity_arg.expect_region()); + outlived_regions.push(identity_arg_idx); } } ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => { @@ -413,7 +424,7 @@ fn live_args_for_outlives_clause<'tcx>( // The bound var doesn't appear in the args at all, so the clause // requires the underlying type to outlive *every* region, which // is equivalent to a `'static` bound. - return Some(FxIndexSet::default()); + return Some(DenseBitSet::new_empty(clause_identity_args.len())); } // The underlying type can capture any arg that's known to outlive one @@ -421,20 +432,13 @@ fn live_args_for_outlives_clause<'tcx>( // region at any use site this clause applies to). let args_known_to_outlive = tcx.args_known_to_outlive_alias_params(alias_def_id); tracing::debug!(?outlived_regions, ?args_known_to_outlive); - let mut capturable_args = FxIndexSet::default(); - for &outlived_region in &outlived_regions { - // There's a bit of a dance here around `Earlybinder::skip_binder` - // and then later a `Earlybinder::bind`. This is because there's - // no real good way today to move the `EarlyBinder` inward - // declaratively without cloning the entire thing. + let mut capturable_args = DenseBitSet::new_empty(clause_identity_args.len()); + for &outlived_arg_idx in &outlived_regions { let (_, outliving_args) = args_known_to_outlive - .as_ref() - .skip_binder() .iter() - .find(|(region, _)| *region == outlived_region) + .find(|(arg_idx, _)| *arg_idx == outlived_arg_idx) .unwrap(); - capturable_args - .extend(outliving_args.iter().copied().map(|a| ty::EarlyBinder::bind(tcx, a))); + capturable_args.union(outliving_args); } Some(capturable_args) } @@ -527,29 +531,18 @@ where | ty::AliasTyKind::Opaque { def_id } | ty::AliasTyKind::Free { def_id } => def_id, }; - let mut capturable: Option< - FxIndexSet>>, - > = None; - let mut restrict = - |capturable_args: FxIndexSet>>| { - match &mut capturable { - None => capturable = Some(capturable_args), - Some(prev) => { - *prev = prev.intersection(&capturable_args).copied().collect() - } - }; + let mut capturable: Option> = None; + let mut restrict = |capturable_args: DenseBitSet| { + match &mut capturable { + None => capturable = Some(capturable_args), + Some(prev) => { + prev.intersect(&capturable_args); + } }; + }; if let Some(live_args) = tcx.live_args_for_alias_from_outlives_bounds(kind) { - restrict( - live_args - .as_ref() - .skip_binder() - .iter() - .copied() - .map(|a| ty::EarlyBinder::bind(tcx, a)) - .collect(), - ); + restrict(live_args.clone()); } for clause in param_env.caller_bounds() { @@ -566,9 +559,8 @@ where match capturable { Some(capturable_args) => { - for arg in capturable_args { - let arg = arg.instantiate(tcx, args).skip_norm_wip(); - arg.visit_with(self); + for idx in capturable_args.iter() { + args[idx].visit_with(self); } } None => { From 9d3a26dde41af228982ae6885e825b83c314075a Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Wed, 12 Aug 2026 11:06:41 -0300 Subject: [PATCH 02/40] Use DenseBitSet for live alias args Match the existing params_in_repr / unsizing_params convention; the compiler already treats generic arg counts as u32-sized. --- compiler/rustc_metadata/src/rmeta/mod.rs | 4 ++-- .../rustc_metadata/src/rmeta/parameterized.rs | 1 - compiler/rustc_middle/src/queries.rs | 4 ++-- .../src/traits/outlives_for_liveness.rs | 24 +++++++++---------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 990f134cafc24..e812a15dc5e98 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -482,8 +482,8 @@ define_tables! { anon_const_kind: Table>, const_of_item: Table>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, - live_args_for_alias_from_outlives_bounds: Table>>>, - args_known_to_outlive_alias_params: Table)>>>, + live_args_for_alias_from_outlives_bounds: Table>>>, + args_known_to_outlive_alias_params: Table)>>>, mut_restriction: Table>, } diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index 346acceba7c1e..75b86f8dda274 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -106,7 +106,6 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_index::bit_set::DenseBitSet, - rustc_index::bit_set::DenseBitSet, rustc_middle::metadata::AmbigModChild, rustc_middle::metadata::ModChild, rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 96cd4f296c354..e76bb4aad921e 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2155,7 +2155,7 @@ rustc_queries! { /// (and so is `T`, since `T: 'static` implies `T: 'a`) /// - `bar` outlives `'static`, so we know that no args are potentially live and we can return an empty set /// - `baz` has no outlives bound, so return `None` and let the caller decide what to do - query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx Option> { + query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx Option> { arena_cache desc { "identifying live args for alias `{:?}`", kind } } @@ -2164,7 +2164,7 @@ rustc_queries! { /// outlive it given only the alias's declared where-clauses. Used for liveness: /// these are the only args whose regions the underlying type of the alias /// could capture while satisfying an outlives bound on that param. - query args_known_to_outlive_alias_params(def_id: DefId) -> &'tcx Vec<(usize, rustc_index::bit_set::DenseBitSet)> { + query args_known_to_outlive_alias_params(def_id: DefId) -> &'tcx Vec<(usize, rustc_index::bit_set::DenseBitSet)> { arena_cache desc { "computing the args known to outlive each region param of alias `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs index f07cbde8a9f1a..a2df25d8abea6 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs @@ -28,7 +28,7 @@ use crate::regions::{region_known_to_outlive, ty_known_to_outlive}; pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, kind: ty::AliasTyKind<'tcx>, -) -> Option> { +) -> Option> { let def_id = match kind { ty::AliasTyKind::Projection { def_id } | ty::AliasTyKind::Inherent { def_id } @@ -99,7 +99,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( let args_known_to_outlive = tcx.args_known_to_outlive_alias_params(def_id); tracing::debug!(?args_known_to_outlive); - let mut live_args: Option> = None; + let mut live_args: Option> = None; for outlives_region in outlives_regions { let Some(outlives_params) = args_known_to_outlive .iter() @@ -128,7 +128,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( pub(crate) fn args_known_to_outlive_alias_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Vec<(usize, DenseBitSet)> { +) -> Vec<(usize, DenseBitSet)> { match tcx.def_kind(def_id) { DefKind::OpaqueTy => args_known_to_outlive_opaque_params(tcx, def_id), DefKind::AssocTy @@ -173,7 +173,7 @@ pub(crate) fn args_known_to_outlive_alias_params<'tcx>( pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Vec<(usize, DenseBitSet)> { +) -> Vec<(usize, DenseBitSet)> { let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let mut result = Vec::new(); @@ -255,7 +255,7 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( } // Types aren't captured, so don't need to map to the opaque - opaque_outlives_args.insert(parent_outlived_arg_idx); + opaque_outlives_args.insert(parent_outlived_arg_idx as u32); } for &(parent_outlives_region, opaque_arg_idx) in parent_outlives_regions.iter() { @@ -272,7 +272,7 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( continue; } - opaque_outlives_args.insert(opaque_arg_idx); + opaque_outlives_args.insert(opaque_arg_idx as u32); } result.push((*opaque_outlived_arg_idx, opaque_outlives_args)); @@ -285,7 +285,7 @@ pub(crate) fn args_known_to_outlive_opaque_params<'tcx>( pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Vec<(usize, DenseBitSet)> { +) -> Vec<(usize, DenseBitSet)> { let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let param_env = tcx.param_env(def_id); tracing::debug!(?param_env); @@ -307,7 +307,7 @@ pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( ty::GenericArgKind::Const(_) => false, }; if outlives { - outliving_args.insert(arg_idx); + outliving_args.insert(arg_idx as u32); } } result.push((outlived_arg_idx, outliving_args)); @@ -354,7 +354,7 @@ fn live_args_for_outlives_clause<'tcx>( alias_def_id: DefId, ty: Ty<'tcx>, outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, -) -> Option> { +) -> Option> { // N.B. it's okay to skip the binder here (and in the rest of the function), // because all variables under binders do not escape let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) = @@ -531,8 +531,8 @@ where | ty::AliasTyKind::Opaque { def_id } | ty::AliasTyKind::Free { def_id } => def_id, }; - let mut capturable: Option> = None; - let mut restrict = |capturable_args: DenseBitSet| { + let mut capturable: Option> = None; + let mut restrict = |capturable_args: DenseBitSet| { match &mut capturable { None => capturable = Some(capturable_args), Some(prev) => { @@ -560,7 +560,7 @@ where match capturable { Some(capturable_args) => { for idx in capturable_args.iter() { - args[idx].visit_with(self); + args[idx as usize].visit_with(self); } } None => { From c4f07b83b97dd8e09fcb3be7283251171a8bee77 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Sun, 16 Aug 2026 16:33:23 -0300 Subject: [PATCH 03/40] Use filled bitsets for alias liveness restrictions Treat missing outlives information as no restriction so all sources can be intersected uniformly. Keep bivariant alias arguments out of the final region walk. --- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/queries.rs | 4 +- .../src/traits/outlives_for_liveness.rs | 92 +++++++------------ 3 files changed, 36 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e812a15dc5e98..279e4402ed4da 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -482,7 +482,7 @@ define_tables! { anon_const_kind: Table>, const_of_item: Table>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, - live_args_for_alias_from_outlives_bounds: Table>>>, + live_args_for_alias_from_outlives_bounds: Table>>, args_known_to_outlive_alias_params: Table)>>>, mut_restriction: Table>, } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index e76bb4aad921e..2c30d45c3c894 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2154,8 +2154,8 @@ rustc_queries! { /// - `foo` outlives `'a`, but we know that `'b: 'a` holds, so `'b` is *also* potentially live /// (and so is `T`, since `T: 'static` implies `T: 'a`) /// - `bar` outlives `'static`, so we know that no args are potentially live and we can return an empty set - /// - `baz` has no outlives bound, so return `None` and let the caller decide what to do - query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx Option> { + /// - `baz` has no outlives bound, so all args are potentially live + query live_args_for_alias_from_outlives_bounds(kind: ty::AliasTyKind<'tcx>) -> &'tcx rustc_index::bit_set::DenseBitSet { arena_cache desc { "identifying live args for alias `{:?}`", kind } } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs index a2df25d8abea6..eb89d79474d1c 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs @@ -18,9 +18,9 @@ use crate::regions::{region_known_to_outlive, ty_known_to_outlive}; /// Callers should use the indices with the concrete args of the alias. /// /// There are three cases to consider: -/// 1. If there are *no* outlives bounds, then we return None. +/// 1. If there are *no* outlives bounds, then all args are potentially live. /// 2. If there is a `'static` outlives bound, then we know that all args are -/// irrelevant, so we return an empty list. +/// irrelevant, so we return an empty set. /// 3. If there are *any* outlives bounds, then we find any args that are known /// to outlive those bounds, since those are the args whose regions the /// underlying type could capture. @@ -28,7 +28,7 @@ use crate::regions::{region_known_to_outlive, ty_known_to_outlive}; pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, kind: ty::AliasTyKind<'tcx>, -) -> Option> { +) -> DenseBitSet { let def_id = match kind { ty::AliasTyKind::Projection { def_id } | ty::AliasTyKind::Inherent { def_id } @@ -70,7 +70,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( // If there are no outlives bounds, then all (non-bivariant) args are potentially live. if outlives_regions.is_empty() { - return None; + return DenseBitSet::new_filled(self_identity_args.len()); } // If any of the outlives bounds are `'static`, then we know the alias @@ -89,7 +89,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( // regions are going to be instantiated with free regions. if outlives_regions.contains(&tcx.lifetimes.re_static) { tracing::debug!("alias has a 'static outlives bound, so skipping visiting any regions"); - return Some(DenseBitSet::new_empty(self_identity_args.len())); + return DenseBitSet::new_empty(self_identity_args.len()); } // Okay, so we know we have some outlives bounds, and that none of them are `'static`. @@ -99,7 +99,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( let args_known_to_outlive = tcx.args_known_to_outlive_alias_params(def_id); tracing::debug!(?args_known_to_outlive); - let mut live_args: Option> = None; + let mut live_args = DenseBitSet::new_filled(self_identity_args.len()); for outlives_region in outlives_regions { let Some(outlives_params) = args_known_to_outlive .iter() @@ -107,13 +107,7 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( else { continue; }; - let new_live_args = outlives_params.1.clone(); - match &mut live_args { - None => live_args = Some(new_live_args), - Some(prev) => { - prev.intersect(&new_live_args); - } - }; + live_args.intersect(&outlives_params.1); } live_args } @@ -347,20 +341,24 @@ pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( /// some cases (like `for<'x, 'y, 'z> T::Assoc<'x, 'y, 'z>: 'x`) that won't /// be satisfiable today, but the logic here should hold whenever there *is*. /// -/// Returns `None` if the clause doesn't apply to `ty` or gives us no information. +/// Returns a filled set if the clause doesn't apply to `ty` or gives us no +/// information. #[tracing::instrument(level = "debug", skip(tcx), ret)] fn live_args_for_outlives_clause<'tcx>( tcx: TyCtxt<'tcx>, alias_def_id: DefId, ty: Ty<'tcx>, outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, -) -> Option> { +) -> DenseBitSet { + let clause_identity_args = ty::GenericArgs::identity_for_item(tcx, alias_def_id); + let no_restriction = || DenseBitSet::new_filled(clause_identity_args.len()); + // N.B. it's okay to skip the binder here (and in the rest of the function), // because all variables under binders do not escape let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) = *outlives.skip_binder().0.kind() else { - return None; + return no_restriction(); }; let clause_def_id = match clause_alias_kind { ty::AliasTyKind::Projection { def_id } @@ -369,27 +367,28 @@ fn live_args_for_outlives_clause<'tcx>( | ty::AliasTyKind::Free { def_id } => def_id, }; if clause_def_id != alias_def_id { - return None; + return no_restriction(); } // Here, we're just using this to check if the clause *could apply* to `ty`, // but importantly we don't want to use the returned region, because that is // the "last visited" region in `ty` that matches the outlves bound. Actually, // we want *all* the identity regions in `ty` that match the outlives bound. - test_type_match::extract_verify_if_eq( + let Some(_) = test_type_match::extract_verify_if_eq( tcx, &outlives.map_bound(|ty::OutlivesClause(ty, bound)| VerifyIfEq { ty, bound }), ty, - )?; + ) else { + return no_restriction(); + }; let outlived_region = outlives.skip_binder().1; - let clause_identity_args = ty::GenericArgs::identity_for_item(tcx, alias_def_id); match outlived_region.kind() { // The underlying type must outlive `'static`, so it can't capture any of the args at all. // // Of course, you may ask: "what if the function has a `'a: 'static` bound?" See the corresponding // comment in `live_args_for_alias_from_outlives_bounds` for why we don't need to worry about that. - ty::ReStatic => Some(DenseBitSet::new_empty(clause_identity_args.len())), + ty::ReStatic => DenseBitSet::new_empty(clause_identity_args.len()), ty::ReBound(_, br) => { // The bound is one of the clause's higher-ranked vars. Find the arg // positions it occupies, then (at the alias's identity level) find @@ -415,7 +414,7 @@ fn live_args_for_outlives_clause<'tcx>( // so conservatively treat the clause as giving no // restriction at all. if clause_arg.has_escaping_bound_vars() { - return None; + return no_restriction(); } } } @@ -424,7 +423,7 @@ fn live_args_for_outlives_clause<'tcx>( // The bound var doesn't appear in the args at all, so the clause // requires the underlying type to outlive *every* region, which // is equivalent to a `'static` bound. - return Some(DenseBitSet::new_empty(clause_identity_args.len())); + return DenseBitSet::new_empty(clause_identity_args.len()); } // The underlying type can capture any arg that's known to outlive one @@ -440,7 +439,7 @@ fn live_args_for_outlives_clause<'tcx>( .unwrap(); capturable_args.union(outliving_args); } - Some(capturable_args) + capturable_args } // A free region (e.g. `for T::Assoc<'a, 'x>: 'x`, where `'x` is free). // This is effectively the same as `for<'a, 'b> T::Assoc<'a, 'b>: 'b`, @@ -463,9 +462,9 @@ fn live_args_for_outlives_clause<'tcx>( // } // ``` // So, we conservatively treat this as giving no restriction on which args can be captured. - ty::ReEarlyParam(..) => None, + ty::ReEarlyParam(..) => no_restriction(), // Don't know that we actually hit this (maybe `ReError`), go ahead and be conservative. - _ => None, + _ => no_restriction(), } } @@ -531,47 +530,22 @@ where | ty::AliasTyKind::Opaque { def_id } | ty::AliasTyKind::Free { def_id } => def_id, }; - let mut capturable: Option> = None; - let mut restrict = |capturable_args: DenseBitSet| { - match &mut capturable { - None => capturable = Some(capturable_args), - Some(prev) => { - prev.intersect(&capturable_args); - } - }; - }; - - if let Some(live_args) = tcx.live_args_for_alias_from_outlives_bounds(kind) { - restrict(live_args.clone()); - } + let mut capturable = tcx.live_args_for_alias_from_outlives_bounds(kind).clone(); for clause in param_env.caller_bounds() { let Some(outlives) = clause.as_type_outlives_clause() else { continue; }; - if let Some(capturable_args) = - live_args_for_outlives_clause(tcx, def_id, ty, outlives) - { - restrict(capturable_args); - } + capturable.intersect(&live_args_for_outlives_clause(tcx, def_id, ty, outlives)); } tracing::debug!(?capturable); - match capturable { - Some(capturable_args) => { - for idx in capturable_args.iter() { - args[idx as usize].visit_with(self); - } - } - None => { - // Skip lifetime parameters that are not captured, since they do - // not need to be live. - let variances = tcx.opt_alias_variances(kind); - for (idx, s) in args.iter().enumerate() { - if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) { - s.visit_with(self); - } - } + // Skip lifetime parameters that are not captured, since they do + // not need to be live. + let variances = tcx.opt_alias_variances(kind); + for idx in capturable.iter() { + if variances.map(|variances| variances[idx as usize]) != Some(ty::Bivariant) { + args[idx as usize].visit_with(self); } } } From 0e3ef39eaf200ee54b7ab904d749dd223e408f52 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 11 Aug 2026 08:44:45 -0300 Subject: [PATCH 04/40] add ui test for usize suggestion on array literal --- .../ui/consts/array-type-usize-suggestion.rs | 9 +++++++ .../consts/array-type-usize-suggestion.stderr | 27 +++++++++++++++++++ .../ui/consts/non-const-value-in-const.stderr | 2 +- .../parser/recover/array-type-no-semi.stderr | 2 +- tests/ui/repeat-expr/repeat_count.stderr | 2 +- 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/ui/consts/array-type-usize-suggestion.rs create mode 100644 tests/ui/consts/array-type-usize-suggestion.stderr diff --git a/tests/ui/consts/array-type-usize-suggestion.rs b/tests/ui/consts/array-type-usize-suggestion.rs new file mode 100644 index 0000000000000..a86613ba8d4df --- /dev/null +++ b/tests/ui/consts/array-type-usize-suggestion.rs @@ -0,0 +1,9 @@ +//@ check-fail + +fn main() { + let length = 3; + let values: [i32; length] = [0; length]; + //~^ ERROR attempt to use a non-constant value in a constant [E0435] + //~| ERROR attempt to use a non-constant value in a constant [E0435] + println!("{}", values.len()); +} diff --git a/tests/ui/consts/array-type-usize-suggestion.stderr b/tests/ui/consts/array-type-usize-suggestion.stderr new file mode 100644 index 0000000000000..aef1cbee06011 --- /dev/null +++ b/tests/ui/consts/array-type-usize-suggestion.stderr @@ -0,0 +1,27 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/array-type-usize-suggestion.rs:5:23 + | +LL | let values: [i32; length] = [0; length]; + | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let length = 3; +LL + const length: usize = 3; + | + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/array-type-usize-suggestion.rs:5:37 + | +LL | let values: [i32; length] = [0; length]; + | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let length = 3; +LL + const length: usize = 3; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index 201c310843b38..67478a4f84727 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -19,7 +19,7 @@ LL | let _ = [0; x]; help: consider using `const` instead of `let` | LL - let x = 5; -LL + const x: /* Type */ = 5; +LL + const x: usize = 5; | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 0af085140223e..01fcc3766f635 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -68,7 +68,7 @@ LL | let c: [i32, x]; help: consider using `const` instead of `let` | LL - let x = 5; -LL + const x: /* Type */ = 5; +LL + const x: usize = 5; | error[E0423]: cannot find value `i32` in this scope diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index e2cecf9973b8b..91d6a5d79d0ac 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -7,7 +7,7 @@ LL | let a = [0; n]; help: consider using `const` instead of `let` | LL - let n = 1; -LL + const n: /* Type */ = 1; +LL + const n: usize = 1; | error[E0308]: mismatched types From 745606ce7c80ca2d5fbd4318cc4171a774574cd3 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 11 Aug 2026 07:54:15 -0300 Subject: [PATCH 05/40] add AnonConstKind::ArrayLength to be used forwards --- compiler/rustc_resolve/src/late.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6493631bcc145..d81f60e3ad889 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -79,6 +79,7 @@ enum AnonConstKind { FieldDefaultValue, InlineConst, ConstArg(IsRepeatExpr), + ArrayLength, } impl PatternSource { @@ -1021,7 +1022,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc } TyKind::Array(element_ty, length) => { self.visit_ty(element_ty); - self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); + self.resolve_anon_const(length, AnonConstKind::ArrayLength); } TyKind::DirectConstArg(expr) => self.resolve_anon_const_manual( true, @@ -5112,7 +5113,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes, - AnonConstKind::ConstArg(_) => { + AnonConstKind::ConstArg(_) | AnonConstKind::ArrayLength => { if self.r.features.generic_const_exprs() || self.r.features.min_generic_const_args() || is_trivial_const_arg From ae53151926463482bdb79652a2c3f2f3bf645292 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 11 Aug 2026 08:08:34 -0300 Subject: [PATCH 06/40] add ConstantSpecificType to pass information forward --- compiler/rustc_resolve/src/ident.rs | 6 +++--- compiler/rustc_resolve/src/late.rs | 29 +++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 000af0f38534a..c74fdaa8f2b9a 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1512,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem)); } } - RibKind::ConstantItem(_, item) => { + RibKind::ConstantItem(_, item, _) => { // Still doesn't deal with upvars if let Some(span) = finalize { let (span, resolution_error) = match item { @@ -1611,7 +1611,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - RibKind::ConstantItem(trivial, _) => { + RibKind::ConstantItem(trivial, _, _) => { if let ConstantHasGenerics::No(cause) = trivial && !matches!(res, Res::SelfTyAlias { .. }) { @@ -1705,7 +1705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - RibKind::ConstantItem(trivial, _) => { + RibKind::ConstantItem(trivial, _, _) => { if let ConstantHasGenerics::No(cause) = trivial { if let Some(span) = finalize { let error = match cause { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d81f60e3ad889..2b913a84c5687 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -137,6 +137,13 @@ pub(crate) enum ConstantHasGenerics { No(NoConstantGenericsReason), } +/// Does this constant requires an specific type? +#[derive(Copy, Clone, Debug)] +pub(crate) enum ConstantRequiresType { + Usize, + No, +} + impl ConstantHasGenerics { fn force_yes_if(self, b: bool) -> Self { if b { Self::Yes } else { self } @@ -215,7 +222,9 @@ pub(crate) enum RibKind<'ra> { /// /// The item may reference generic parameters in trivial constant expressions. /// All other constants aren't allowed to use generic params at all. - ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), + /// + /// If the constant comes from specific contexts (like array length) it might require an specific type. + ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>, ConstantRequiresType), /// We passed through a module item. Module(LocalModule<'ra>), @@ -2996,6 +3005,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_constant_rib( IsRepeatExpr::No, ConstantHasGenerics::Yes, + ConstantRequiresType::No, Some((ConstBlockItem::IDENT, ConstantItemKind::Const)), |this| this.resolve_labeled_block(None, block.id, block), ) @@ -3270,19 +3280,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, is_repeat: IsRepeatExpr, may_use_generics: ConstantHasGenerics, + requires_type: ConstantRequiresType, item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { let f = |this: &mut Self| { - this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| { + this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item, requires_type), |this| { this.with_rib( TypeNS, RibKind::ConstantItem( may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), item, + requires_type ), |this| { - this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f); + this.with_label_rib(RibKind::ConstantItem(may_use_generics, item, requires_type), f); }, ) }) @@ -3840,7 +3852,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_static_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| { - this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| { + this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, ConstantRequiresType::No, item, |this| { this.visit_expr(expr) }); }) @@ -3853,7 +3865,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) { if let Some(body) = body { self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| { - this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| { + this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, ConstantRequiresType::No, item, |this| { this.visit_expr(body) }) }) @@ -5125,7 +5137,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }; - self.with_constant_rib(is_repeat_expr, may_use_generics, None, |this| { + let requires_type = match anon_const_kind { + AnonConstKind::ArrayLength | AnonConstKind::ConstArg(IsRepeatExpr::Yes) => ConstantRequiresType::Usize, + _ => ConstantRequiresType::No, + }; + + self.with_constant_rib(is_repeat_expr, may_use_generics, requires_type, None, |this| { this.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| { resolve_expr(this); }); From edcfc0d5f3ad71d66e0398bae4bbb58c951fdd29 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 11 Aug 2026 08:31:30 -0300 Subject: [PATCH 07/40] wire specific type into diagnostic --- compiler/rustc_resolve/src/diagnostics/impls.rs | 2 ++ compiler/rustc_resolve/src/diagnostics/mod.rs | 3 ++- compiler/rustc_resolve/src/ident.rs | 9 ++++++++- compiler/rustc_resolve/src/lib.rs | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index fb0d344fc3da7..49da27f77813e 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1173,6 +1173,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion, current, type_span, + type_name } => { // let foo =... // ^^^ given this Span @@ -1214,6 +1215,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion, current, type_span, + type_name }), Some(diagnostics::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }), None, diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index d4ce0dc78ca1f..a8fe5f70ac058 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -298,8 +298,9 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { #[suggestion_part(code = "{suggestion} ")] pub(crate) span: Span, pub(crate) suggestion: &'a str, - #[suggestion_part(code = ": /* Type */")] + #[suggestion_part(code = ": {type_name}")] pub(crate) type_span: Option, + pub(crate) type_name: &'a str, pub(crate) current: &'a str, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index c74fdaa8f2b9a..bd7b1b51929af 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1512,9 +1512,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem)); } } - RibKind::ConstantItem(_, item, _) => { + RibKind::ConstantItem(_, item, requires_type) => { // Still doesn't deal with upvars if let Some(span) = finalize { + let type_name = match requires_type { + crate::late::ConstantRequiresType::Usize => "usize", + crate::late::ConstantRequiresType::No => "/* Type */", + }; + let (span, resolution_error) = match item { None if rib_ident.name == kw::SelfLower => { (span, LowercaseSelf) @@ -1541,6 +1546,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion: "const", current: "let", type_span, + type_name, }, ) } @@ -1551,6 +1557,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion: "let", current: kind.as_str(), type_span: None, + type_name: "", }, ), }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2b02fe136f2ad..d7d519ee00d5d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -283,6 +283,7 @@ enum ResolutionError<'ra> { suggestion: &'static str, current: &'static str, type_span: Option, + type_name: &'static str }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { From 5f56642ce2d48648d2280d5c574eb1fdfdd9f82f Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 11 Aug 2026 09:31:18 -0300 Subject: [PATCH 08/40] x fmt (so tidy checks) --- .../rustc_resolve/src/diagnostics/impls.rs | 2 +- compiler/rustc_resolve/src/late.rs | 57 ++++++++++++------- compiler/rustc_resolve/src/lib.rs | 2 +- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 49da27f77813e..1c1883e238fcb 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1173,7 +1173,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion, current, type_span, - type_name + type_name, } => { // let foo =... // ^^^ given this Span diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2b913a84c5687..1549babc6793c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3285,19 +3285,26 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { f: impl FnOnce(&mut Self), ) { let f = |this: &mut Self| { - this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item, requires_type), |this| { - this.with_rib( - TypeNS, - RibKind::ConstantItem( - may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), - item, - requires_type - ), - |this| { - this.with_label_rib(RibKind::ConstantItem(may_use_generics, item, requires_type), f); - }, - ) - }) + this.with_rib( + ValueNS, + RibKind::ConstantItem(may_use_generics, item, requires_type), + |this| { + this.with_rib( + TypeNS, + RibKind::ConstantItem( + may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), + item, + requires_type, + ), + |this| { + this.with_label_rib( + RibKind::ConstantItem(may_use_generics, item, requires_type), + f, + ); + }, + ) + }, + ) }; if let ConstantHasGenerics::No(cause) = may_use_generics { @@ -3852,9 +3859,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_static_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| { - this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, ConstantRequiresType::No, item, |this| { - this.visit_expr(expr) - }); + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + ConstantRequiresType::No, + item, + |this| this.visit_expr(expr), + ); }) } @@ -3865,9 +3876,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) { if let Some(body) = body { self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| { - this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, ConstantRequiresType::No, item, |this| { - this.visit_expr(body) - }) + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + ConstantRequiresType::No, + item, + |this| this.visit_expr(body), + ) }) } } @@ -5138,7 +5153,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; let requires_type = match anon_const_kind { - AnonConstKind::ArrayLength | AnonConstKind::ConstArg(IsRepeatExpr::Yes) => ConstantRequiresType::Usize, + AnonConstKind::ArrayLength | AnonConstKind::ConstArg(IsRepeatExpr::Yes) => { + ConstantRequiresType::Usize + } _ => ConstantRequiresType::No, }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d7d519ee00d5d..63c297519c9f1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -283,7 +283,7 @@ enum ResolutionError<'ra> { suggestion: &'static str, current: &'static str, type_span: Option, - type_name: &'static str + type_name: &'static str, }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { From 520b339284b20d5b1b7d7eb7d6ac36e379c5f15e Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Wed, 19 Aug 2026 16:49:21 -0300 Subject: [PATCH 09/40] Split diagnostic to avoid has-placeholder on fixed one --- .../rustc_resolve/src/diagnostics/impls.rs | 27 ++++++++---- compiler/rustc_resolve/src/diagnostics/mod.rs | 41 ++++++++++++------- compiler/rustc_resolve/src/ident.rs | 9 +--- compiler/rustc_resolve/src/lib.rs | 6 +-- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 1c1883e238fcb..963a7336a80af 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -50,7 +50,7 @@ use crate::diagnostics::{ }; use crate::hygiene::Macros20NormalizedSyntaxContext; use crate::imports::{Import, ImportKind, UnresolvedImportError, import_path_to_string}; -use crate::late::{DiagMetadata, PatternSource, Rib}; +use crate::late::{ConstantRequiresType, DiagMetadata, PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind, DelayedVisResolutionError, Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, @@ -1173,7 +1173,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion, current, type_span, - type_name, + requires_type, } => { // let foo =... // ^^^ given this Span @@ -1210,12 +1210,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if is_simple_binding { ( - Some(diagnostics::AttemptToUseNonConstantValueInConstantWithSuggestion { - span: sp, - suggestion, - current, - type_span, - type_name + Some(match requires_type { + ConstantRequiresType::Usize => { + diagnostics::AttemptToUseNonConstantValueInConstantWithSuggestion::Usize { + span: sp, + suggestion, + current, + type_span, + } + } + ConstantRequiresType::No => { + diagnostics::AttemptToUseNonConstantValueInConstantWithSuggestion::Placeholder { + span: sp, + suggestion, + current, + type_span, + } + } }), Some(diagnostics::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }), None, diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index a8fe5f70ac058..e86717a7a3191 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -288,20 +288,33 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { } #[derive(Subdiagnostic)] -#[multipart_suggestion( - "consider using `{$suggestion}` instead of `{$current}`", - style = "verbose", - applicability = "has-placeholders" -)] -pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { - // #[primary_span] - #[suggestion_part(code = "{suggestion} ")] - pub(crate) span: Span, - pub(crate) suggestion: &'a str, - #[suggestion_part(code = ": {type_name}")] - pub(crate) type_span: Option, - pub(crate) type_name: &'a str, - pub(crate) current: &'a str, +pub(crate) enum AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { + #[multipart_suggestion( + "consider using `{$suggestion}` instead of `{$current}`", + style = "verbose", + applicability = "has-placeholders" + )] + Placeholder { + #[suggestion_part(code = "{suggestion} ")] + span: Span, + suggestion: &'a str, + #[suggestion_part(code = ": /* Type */")] + type_span: Option, + current: &'a str, + }, + #[multipart_suggestion( + "consider using `{$suggestion}` instead of `{$current}`", + style = "verbose", + applicability = "machine-applicable" + )] + Usize { + #[suggestion_part(code = "{suggestion} ")] + span: Span, + suggestion: &'a str, + #[suggestion_part(code = ": usize")] + type_span: Option, + current: &'a str, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index bd7b1b51929af..4ff1554bba68a 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1515,11 +1515,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::ConstantItem(_, item, requires_type) => { // Still doesn't deal with upvars if let Some(span) = finalize { - let type_name = match requires_type { - crate::late::ConstantRequiresType::Usize => "usize", - crate::late::ConstantRequiresType::No => "/* Type */", - }; - let (span, resolution_error) = match item { None if rib_ident.name == kw::SelfLower => { (span, LowercaseSelf) @@ -1546,7 +1541,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion: "const", current: "let", type_span, - type_name, + requires_type, }, ) } @@ -1557,7 +1552,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion: "let", current: kind.as_str(), type_span: None, - type_name: "", + requires_type, }, ), }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 63c297519c9f1..bcd190a34aacc 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -32,8 +32,8 @@ use effective_visibilities::EffectiveVisibilitiesVisitor; use hygiene::Macros20NormalizedSyntaxContext; use imports::{Import, ImportData, ImportKind, NameResolution, PendingDecl}; use late::{ - ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, - UnnecessaryQualification, + ConstantRequiresType, ForwardGenericParamBanReason, HasGenericParams, PathSource, + PatternSource, UnnecessaryQualification, }; pub use macros::registered_lint_tools_ast; use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; @@ -283,7 +283,7 @@ enum ResolutionError<'ra> { suggestion: &'static str, current: &'static str, type_span: Option, - type_name: &'static str, + requires_type: ConstantRequiresType, }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { From 5db7af4118ec82436c4eea711f581b245806868d Mon Sep 17 00:00:00 2001 From: ozankenangungor Date: Thu, 20 Aug 2026 16:44:50 +0300 Subject: [PATCH 10/40] Improve diagnostics for references to closures --- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 3 + compiler/rustc_hir_typeck/src/upvar.rs | 77 ++++++++++ .../src/error_reporting/mod.rs | 9 ++ .../traits/fulfillment_errors.rs | 72 ++++++--- ...osure-ref-fn-kind-mismatch-issue-161327.rs | 73 +++++++++ ...e-ref-fn-kind-mismatch-issue-161327.stderr | 145 ++++++++++++++++++ 6 files changed, 356 insertions(+), 23 deletions(-) create mode 100644 tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.rs create mode 100644 tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 20fa6d5f7a344..4cd2624ee40ef 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -210,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } steps }), + infer_closure_kind: Box::new(|closure_def_id| { + self.infer_closure_kind_for_diagnostic(closure_def_id) + }), } } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 91771fb37d18a..0462fd118e91a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -81,6 +81,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // it's our job to process these. assert!(self.deferred_call_resolutions.borrow().is_empty()); } + + pub(crate) fn infer_closure_kind_for_diagnostic( + &self, + closure_def_id: LocalDefId, + ) -> Option<(ty::ClosureKind, Option<(Span, Place<'tcx>)>)> { + let hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); + let hir::Node::Expr(expr) = self.tcx.hir_node_by_def_id(closure_def_id) else { + return None; + }; + let hir::ExprKind::Closure(&hir::Closure { + capture_clause, + body: body_id, + explicit_captures, + .. + }) = expr.kind + else { + return None; + }; + let body = self.tcx.hir_body(body_id); + + // We cannot reliably infer the closure kind if there are nested closures whose + // captures have not yet been analyzed. + struct HasNestedClosure(bool); + impl<'v> Visitor<'v> for HasNestedClosure { + fn visit_expr(&mut self, expr: &'v hir::Expr<'v>) { + if matches!(expr.kind, hir::ExprKind::Closure(..)) { + self.0 = true; + return; + } + intravisit::walk_expr(self, expr); + } + } + let mut has_nested = HasNestedClosure(false); + has_nested.visit_body(body); + if has_nested.0 { + return None; + } + + let closure_fcx = FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id); + + let mut delegate = InferBorrowKind { + fcx: &closure_fcx, + closure_def_id, + capture_information: Default::default(), + fake_reads: Default::default(), + }; + + let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body); + + for capture in explicit_captures { + let place = closure_fcx.place_for_root_variable(closure_def_id, capture.var_hir_id); + delegate.consume(&PlaceWithHirId { hir_id: capture.var_hir_id, place }, hir_id); + } + + let (_, closure_kind, mut origin) = self + .process_collected_capture_information(capture_clause, &delegate.capture_information); + + // Bail out if a by-value capture has unresolved inference variables, since + // fallback might later resolve the type to `Copy` (making the closure `Fn`). + if closure_kind == ty::ClosureKind::FnOnce { + for (place, capture_info) in &delegate.capture_information { + if matches!(capture_info.capture_kind, ty::UpvarCapture::ByValue) + && place.ty().has_infer() + { + return None; + } + } + } + + if !enable_precise_capture(expr.span) { + if let Some((_, ref mut place)) = origin { + place.projections.clear(); + } + } + + Some((closure_kind, origin)) + } } /// Intermediate format to store the hir_id pointing to the use that resulted in the diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs index ff0ac4fcfbe6a..58964492c4837 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs @@ -25,6 +25,14 @@ pub struct TypeErrCtxt<'a, 'tcx> { pub diverging_fallback_has_occurred: bool, pub autoderef_steps: Box) -> Vec<(Ty<'tcx>, PredicateObligations<'tcx>)> + 'a>, + pub infer_closure_kind: Box< + dyn Fn( + rustc_hir::def_id::LocalDefId, + ) -> Option<( + ty::ClosureKind, + Option<(rustc_span::Span, rustc_middle::hir::place::Place<'tcx>)>, + )> + 'a, + >, } #[extension(pub trait InferCtxtErrorExt<'tcx>)] @@ -41,6 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); vec![(ty, PredicateObligations::new())] }), + infer_closure_kind: Box::new(|_| None), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6293c85f595d8..7881d4c5d4404 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -996,18 +996,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let self_ty = trait_pred.self_ty().skip_binder(); + let original_self_ty = trait_pred.self_ty().skip_binder(); + let peeled_self_ty = original_self_ty.peel_refs(); - let (expected_kind, trait_prefix) = + let is_ref_to_closure = matches!(original_self_ty.kind(), ty::Ref(..)) + && matches!(peeled_self_ty.kind(), ty::Closure(..)); + + let self_ty = if is_ref_to_closure { peeled_self_ty } else { original_self_ty }; + + let (expected_kind, is_async) = if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { - (expected_kind, "") + (expected_kind, false) } else if let Some(expected_kind) = self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id()) { - (expected_kind, "Async") + (expected_kind, true) } else { return None; }; + let trait_prefix = if is_async { "Async" } else { "" }; let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() { ty::Closure(def_id, args) => { @@ -1036,7 +1043,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; } - if let Some(found_kind) = self.closure_kind(self_ty) + let mut found_kind = self.closure_kind(self_ty); + let mut kind_origin = None; + + if found_kind.is_none() + && is_ref_to_closure + && !is_async + && let Some(local_def_id) = closure_def_id.as_local() + && let Some((inferred_kind, origin)) = (self.infer_closure_kind)(local_def_id) + { + found_kind = Some(inferred_kind); + kind_origin = origin; + } + + if let Some(found_kind) = found_kind && !found_kind.extends(expected_kind) { let mut err = self.report_closure_error( @@ -1045,6 +1065,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { found_kind, expected_kind, trait_prefix, + kind_origin, ); self.note_obligation_cause(&mut err, &obligation); return Some(err.emit()); @@ -3526,6 +3547,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { found_kind: ty::ClosureKind, kind: ty::ClosureKind, trait_prefix: &'static str, + kind_origin: Option<(Span, rustc_middle::hir::place::Place<'tcx>)>, ) -> Diag<'a> { let closure_span = self.tcx.def_span(closure_def_id); @@ -3541,25 +3563,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Additional context information explaining why the closure only implements // a particular trait. - if let Some(typeck_results) = &self.typeck_results { - let hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id.expect_local()); - match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, place))) => { - err.fn_once_label = Some(ClosureFnOnceLabel { - span: *span, - place: ty::place_to_string_for_capture(self.tcx, place), - trait_prefix, - }) - } - (ty::ClosureKind::FnMut, Some((span, place))) => { - err.fn_mut_label = Some(ClosureFnMutLabel { - span: *span, - place: ty::place_to_string_for_capture(self.tcx, place), - trait_prefix, - }) - } - _ => {} + let origin = kind_origin.or_else(|| { + let typeck_results = self.typeck_results.as_ref()?; + let local_def_id = closure_def_id.as_local()?; + let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); + typeck_results.closure_kind_origins().get(hir_id).cloned() + }); + + match (found_kind, origin) { + (ty::ClosureKind::FnOnce, Some((span, place))) => { + err.fn_once_label = Some(ClosureFnOnceLabel { + span, + place: ty::place_to_string_for_capture(self.tcx, &place), + trait_prefix, + }) } + (ty::ClosureKind::FnMut, Some((span, place))) => { + err.fn_mut_label = Some(ClosureFnMutLabel { + span, + place: ty::place_to_string_for_capture(self.tcx, &place), + trait_prefix, + }) + } + _ => {} } self.dcx().create_err(err) diff --git a/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.rs b/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.rs new file mode 100644 index 0000000000000..8233d6034a40a --- /dev/null +++ b/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.rs @@ -0,0 +1,73 @@ +fn req_fn(_: impl Fn(&'static str) -> String) {} +fn req_fn_mut(_: impl FnMut(&'static str) -> String) {} + +fn test_fn_mut_passed_as_mut_ref_to_fn() { + let mut v = Vec::new(); + let mut accumulate = |x| { + //~^ ERROR E0525 + v.push(x); + v.join("/") + }; + req_fn(&mut accumulate); +} + +fn test_fn_once_passed_as_mut_ref_to_fn() { + let s = String::new(); + let mut consume = move |_x| { + //~^ ERROR E0525 + drop(s); + String::new() + }; + req_fn(&mut consume); +} + +fn test_fn_once_passed_as_mut_ref_to_fn_mut() { + let s = String::new(); + let mut consume = move |_x| { + //~^ ERROR E0525 + drop(s); + String::new() + }; + req_fn_mut(&mut consume); +} + +fn test_double_ref_fn_mut_passed_to_fn() { + let mut v = Vec::new(); + let mut accumulate = |x| { + //~^ ERROR E0525 + v.push(x); + v.join("/") + }; + req_fn(&mut &mut accumulate); +} + +fn test_fn_passed_as_mut_ref_to_fn() { + let mut pure_closure = |x: &'static str| x.to_string(); + req_fn(&mut pure_closure); + //~^ ERROR E0277 +} + +fn test_nested_closure_conservative_fallback() { + let mut v = Vec::new(); + let s = String::new(); + let mut outer = |_x| { + v.push("a"); + let inner = || drop(s); + inner(); + v.join("/") + }; + req_fn(&mut outer); + //~^ ERROR E0277 +} + +fn test_unresolved_integer_fallback_copy() { + let x = 0; + let mut c = |_x| { + let _y = x; + String::new() + }; + req_fn(&mut c); + //~^ ERROR E0277 +} + +fn main() {} diff --git a/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.stderr b/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.stderr new file mode 100644 index 0000000000000..dfc657f6c3a00 --- /dev/null +++ b/tests/ui/closures/closure-ref-fn-kind-mismatch-issue-161327.stderr @@ -0,0 +1,145 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:6:26 + | +LL | let mut accumulate = |x| { + | ^^^ this closure implements `FnMut`, not `Fn` +LL | +LL | v.push(x); + | - closure is `FnMut` because it mutates the variable `v` here +... +LL | req_fn(&mut accumulate); + | ------ --------------- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:16:23 + | +LL | let mut consume = move |_x| { + | ^^^^^^^^^ this closure implements `FnOnce`, not `Fn` +LL | +LL | drop(s); + | - closure is `FnOnce` because it moves the variable `s` out of its environment +... +LL | req_fn(&mut consume); + | ------ ------------ the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` + +error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:26:23 + | +LL | let mut consume = move |_x| { + | ^^^^^^^^^ this closure implements `FnOnce`, not `FnMut` +LL | +LL | drop(s); + | - closure is `FnOnce` because it moves the variable `s` out of its environment +... +LL | req_fn_mut(&mut consume); + | ---------- ------- the requirement to implement `FnMut` derives from here + | | + | required by a bound introduced by this call + | + = note: required for `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:26:23: 26:32}` to implement `FnMut(&'static str)` +note: required by a bound in `req_fn_mut` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:2:23 + | +LL | fn req_fn_mut(_: impl FnMut(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn_mut` + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:36:26 + | +LL | let mut accumulate = |x| { + | ^^^ this closure implements `FnMut`, not `Fn` +LL | +LL | v.push(x); + | - closure is `FnMut` because it mutates the variable `v` here +... +LL | req_fn(&mut &mut accumulate); + | ------ -------------------- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` + +error[E0277]: expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:45:28: 45:45}` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:46:12 + | +LL | req_fn(&mut pure_closure); + | ------ ^^^^^^^^^^^^^^^^^ expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:45:28: 45:45}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn(&'static str)` is not implemented for `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:45:28: 45:45}` +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` +help: consider removing the leading `&`-reference + | +LL - req_fn(&mut pure_closure); +LL + req_fn(pure_closure); + | + +error[E0277]: expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:53:21: 53:25}` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:59:12 + | +LL | req_fn(&mut outer); + | ------ ^^^^^^^^^^ expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:53:21: 53:25}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn(&'static str)` is not implemented for `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:53:21: 53:25}` +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` +help: consider removing the leading `&`-reference + | +LL - req_fn(&mut outer); +LL + req_fn(outer); + | + +error[E0277]: expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:65:17: 65:21}` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:69:12 + | +LL | req_fn(&mut c); + | ------ ^^^^^^ expected an `Fn(&'static str)` closure, found `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:65:17: 65:21}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn(&'static str)` is not implemented for `&mut {closure@$DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:65:17: 65:21}` +note: required by a bound in `req_fn` + --> $DIR/closure-ref-fn-kind-mismatch-issue-161327.rs:1:19 + | +LL | fn req_fn(_: impl Fn(&'static str) -> String) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `req_fn` +help: consider removing the leading `&`-reference + | +LL - req_fn(&mut c); +LL + req_fn(c); + | + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0525. +For more information about an error, try `rustc --explain E0277`. From b8e119e084ad3582adee41172f04d33ef4aec375 Mon Sep 17 00:00:00 2001 From: Yukang Date: Mon, 24 Aug 2026 17:13:08 +0800 Subject: [PATCH 11/40] Add regression tests for FnMut closure reference diagnostics --- .../fnmut-shared-reference-requires-fn.rs | 11 +++++++++ .../fnmut-shared-reference-requires-fn.stderr | 23 +++++++++++++++++++ ...hared-reference-suggestion-issue-118843.rs | 10 ++++++++ ...d-reference-suggestion-issue-118843.stderr | 20 ++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 tests/ui/closures/fnmut-shared-reference-requires-fn.rs create mode 100644 tests/ui/closures/fnmut-shared-reference-requires-fn.stderr create mode 100644 tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs create mode 100644 tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr diff --git a/tests/ui/closures/fnmut-shared-reference-requires-fn.rs b/tests/ui/closures/fnmut-shared-reference-requires-fn.rs new file mode 100644 index 0000000000000..1207bc4cf1d52 --- /dev/null +++ b/tests/ui/closures/fnmut-shared-reference-requires-fn.rs @@ -0,0 +1,11 @@ +//! Do not suggest a mutable reference when the root obligation genuinely requires `Fn`. + +fn requires_fn(_: F) {} + +fn main() { + let mut value = 0; + let mut func = || value += 1; + //~^ ERROR expected a closure that implements the `Fn` trait + + requires_fn(&func); +} diff --git a/tests/ui/closures/fnmut-shared-reference-requires-fn.stderr b/tests/ui/closures/fnmut-shared-reference-requires-fn.stderr new file mode 100644 index 0000000000000..6a62f4d1a74c1 --- /dev/null +++ b/tests/ui/closures/fnmut-shared-reference-requires-fn.stderr @@ -0,0 +1,23 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/fnmut-shared-reference-requires-fn.rs:7:20 + | +LL | let mut func = || value += 1; + | ^^ ----- closure is `FnMut` because it mutates the variable `value` here + | | + | this closure implements `FnMut`, not `Fn` +... +LL | requires_fn(&func); + | ----------- ---- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | + = note: required for `&{closure@$DIR/fnmut-shared-reference-requires-fn.rs:7:20: 7:22}` to implement `Fn()` +note: required by a bound in `requires_fn` + --> $DIR/fnmut-shared-reference-requires-fn.rs:3:19 + | +LL | fn requires_fn(_: F) {} + | ^^^^ required by this bound in `requires_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0525`. diff --git a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs new file mode 100644 index 0000000000000..9418246ef3e6d --- /dev/null +++ b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs @@ -0,0 +1,10 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/118843. +//! A shared reference to an `FnMut` closure should suggest a mutable reference. + +fn main() { + let mut value = 0; + let mut func = |increment: usize| value += increment; + //~^ ERROR expected a closure that implements the `Fn` trait + + (0..100).for_each(&func); +} diff --git a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr new file mode 100644 index 0000000000000..a58b6a91f864b --- /dev/null +++ b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr @@ -0,0 +1,20 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/fnmut-shared-reference-suggestion-issue-118843.rs:6:20 + | +LL | let mut func = |increment: usize| value += increment; + | ^^^^^^^^^^^^^^^^^^ ----- closure is `FnMut` because it mutates the variable `value` here + | | + | this closure implements `FnMut`, not `Fn` +... +LL | (0..100).for_each(&func); + | -------- ---- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | + = note: required for `&{closure@$DIR/fnmut-shared-reference-suggestion-issue-118843.rs:6:20: 6:38}` to implement `FnMut(usize)` +note: required by a bound in `for_each` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0525`. From 61d3b06bd85f512a1ee55271d0496dbd717ec863 Mon Sep 17 00:00:00 2001 From: Yukang Date: Mon, 24 Aug 2026 17:20:54 +0800 Subject: [PATCH 12/40] Suggest mutable references for FnMut closure arguments --- .../traits/fulfillment_errors.rs | 21 ++++++++++++++++++- ...ed-reference-suggestion-issue-118843.fixed | 13 ++++++++++++ ...hared-reference-suggestion-issue-118843.rs | 3 +++ ...d-reference-suggestion-issue-118843.stderr | 8 +++++-- 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.fixed diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 082c312c7c75e..d2bb518fac492 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1046,6 +1046,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expected_kind, trait_prefix, ); + self.suggest_change_mut_ref_for_closure(&mut err, &obligation); self.note_obligation_cause(&mut err, &obligation); return Some(err.emit()); } @@ -3019,6 +3020,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } + fn suggest_change_mut_ref_for_closure( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() + && let (_, Some(root_trait_pred)) = + obligation.cause.code().peel_derives_with_predicate() + && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) + && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) = arg.kind + { + let mut obligation = obligation.clone(); + // Error reporting may narrow the cause span to the borrow's operand. + // Use the whole argument so `suggest_change_mut` can replace the shared borrow. + obligation.cause.span = arg.span; + self.suggest_change_mut(&obligation, err, root_trait_pred); + } + } + pub fn note_obligation_cause( &self, err: &mut Diag<'_>, @@ -3557,7 +3577,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => {} } } - self.dcx().create_err(err) } diff --git a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.fixed b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.fixed new file mode 100644 index 0000000000000..1918d26ac2d90 --- /dev/null +++ b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix + +//! Regression test for https://github.com/rust-lang/rust/issues/118843. +//! A shared reference to an `FnMut` closure should suggest a mutable reference. + +fn main() { + let mut value = 0; + let mut func = |increment: usize| value += increment; + //~^ ERROR expected a closure that implements the `Fn` trait + + (0..100).for_each(&mut func); + //~^ HELP consider changing this borrow's mutability +} diff --git a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs index 9418246ef3e6d..d7bd2fb60398a 100644 --- a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs +++ b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.rs @@ -1,3 +1,5 @@ +//@ run-rustfix + //! Regression test for https://github.com/rust-lang/rust/issues/118843. //! A shared reference to an `FnMut` closure should suggest a mutable reference. @@ -7,4 +9,5 @@ fn main() { //~^ ERROR expected a closure that implements the `Fn` trait (0..100).for_each(&func); + //~^ HELP consider changing this borrow's mutability } diff --git a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr index a58b6a91f864b..817c073e92aa8 100644 --- a/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr +++ b/tests/ui/closures/fnmut-shared-reference-suggestion-issue-118843.stderr @@ -1,5 +1,5 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` - --> $DIR/fnmut-shared-reference-suggestion-issue-118843.rs:6:20 + --> $DIR/fnmut-shared-reference-suggestion-issue-118843.rs:8:20 | LL | let mut func = |increment: usize| value += increment; | ^^^^^^^^^^^^^^^^^^ ----- closure is `FnMut` because it mutates the variable `value` here @@ -11,9 +11,13 @@ LL | (0..100).for_each(&func); | | | required by a bound introduced by this call | - = note: required for `&{closure@$DIR/fnmut-shared-reference-suggestion-issue-118843.rs:6:20: 6:38}` to implement `FnMut(usize)` + = note: required for `&{closure@$DIR/fnmut-shared-reference-suggestion-issue-118843.rs:8:20: 8:38}` to implement `FnMut(usize)` note: required by a bound in `for_each` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider changing this borrow's mutability + | +LL | (0..100).for_each(&mut func); + | +++ error: aborting due to 1 previous error From 2b0faa22c7d1f3a879a1acb1cc297e141b1250b2 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 25 Aug 2026 09:29:13 +1000 Subject: [PATCH 13/40] Add more splat fn type tests --- tests/ui/splat/splat-invalid.rs | 25 ++++++++++++++- tests/ui/splat/splat-invalid.stderr | 46 ++++++++++++++++++++++++++- tests/ui/splat/splat-non-tuple.rs | 5 +++ tests/ui/splat/splat-non-tuple.stderr | 8 ++++- 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/tests/ui/splat/splat-invalid.rs b/tests/ui/splat/splat-invalid.rs index a9586b056d8e7..9a0101636a8b0 100644 --- a/tests/ui/splat/splat-invalid.rs +++ b/tests/ui/splat/splat-invalid.rs @@ -61,4 +61,27 @@ impl FooTrait for Foo { fn no_splat(#[rustc_splat] _: (u32, f64)) {} //~ ERROR method `no_splat` has an incompatible type for trait } -fn main() {} +#[rustfmt::skip] +fn main() { + let multisplat_fn_bad_: + fn(#[rustc_splat] (u32, i8), #[rustc_splat] (u32, i8)) = multisplat_fn_bad; + //~^ ERROR multiple `#[rustc_splat]`s are not allowed in the same function argument list + let multisplat_arg_bad_: fn( + #[rustc_splat] + #[rustc_splat] + (u32, i8), + ) = multisplat_arg_bad; + let multisplat_arg_fn_bad_: fn( + #[rustc_splat] + //~^ ERROR multiple `#[rustc_splat]`s are not allowed in the same function argument list + #[rustc_splat] + (u32, i8), + #[rustc_splat] (u32, i8), + ) = multisplat_arg_fn_bad; + + let splat_variadic_: unsafe extern "C" fn(#[rustc_splat] (u32, i8), ...) = splat_variadic; + //~^ ERROR `...` and `#[rustc_splat]` are not allowed in the same function argument list + let splat_variadic2_: unsafe extern "C" fn(..., #[rustc_splat] (u32, i8)) = splat_variadic2; + //~^ ERROR `...` must be the last argument of a C-variadic function + //~| ERROR `...` and `#[rustc_splat]` are not allowed in the same function argument list +} diff --git a/tests/ui/splat/splat-invalid.stderr b/tests/ui/splat/splat-invalid.stderr index 771556d3e91a9..f1c492bd3e37e 100644 --- a/tests/ui/splat/splat-invalid.stderr +++ b/tests/ui/splat/splat-invalid.stderr @@ -87,6 +87,50 @@ LL | fn splat_variadic4(..., #[rustc_splat] (_a, _b): (u32, i8)) {} | = help: remove `#[rustc_splat]` or remove `...` +error: multiple `#[rustc_splat]`s are not allowed in the same function argument list + --> $DIR/splat-invalid.rs:67:12 + | +LL | fn(#[rustc_splat] (u32, i8), #[rustc_splat] (u32, i8)) = multisplat_fn_bad; + | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ + | + = help: remove `#[rustc_splat]` from all but one argument + +error: multiple `#[rustc_splat]`s are not allowed in the same function argument list + --> $DIR/splat-invalid.rs:75:9 + | +LL | #[rustc_splat] + | ^^^^^^^^^^^^^^ +LL | +LL | #[rustc_splat] + | ^^^^^^^^^^^^^^ +LL | (u32, i8), +LL | #[rustc_splat] (u32, i8), + | ^^^^^^^^^^^^^^ + | + = help: remove `#[rustc_splat]` from all but one argument + +error: `...` and `#[rustc_splat]` are not allowed in the same function argument list + --> $DIR/splat-invalid.rs:82:47 + | +LL | let splat_variadic_: unsafe extern "C" fn(#[rustc_splat] (u32, i8), ...) = splat_variadic; + | ^^^^^^^^^^^^^^ ^^^ + | + = help: remove `#[rustc_splat]` or remove `...` + +error: `...` must be the last argument of a C-variadic function + --> $DIR/splat-invalid.rs:84:48 + | +LL | let splat_variadic2_: unsafe extern "C" fn(..., #[rustc_splat] (u32, i8)) = splat_variadic2; + | ^^^ + +error: `...` and `#[rustc_splat]` are not allowed in the same function argument list + --> $DIR/splat-invalid.rs:84:48 + | +LL | let splat_variadic2_: unsafe extern "C" fn(..., #[rustc_splat] (u32, i8)) = splat_variadic2; + | ^^^ ^^^^^^^^^^^^^^ + | + = help: remove `#[rustc_splat]` or remove `...` + error: multiple `rustc_splat` attributes --> $DIR/splat-invalid.rs:11:5 | @@ -139,6 +183,6 @@ LL | fn no_splat(_: (u32, f64)); = note: expected signature `fn((_, _))` found signature `fn(#[rustc_splat] (_, _))` -error: aborting due to 14 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/splat/splat-non-tuple.rs b/tests/ui/splat/splat-non-tuple.rs index e1b115432d788..a11d94a1fbb99 100644 --- a/tests/ui/splat/splat-non-tuple.rs +++ b/tests/ui/splat/splat-non-tuple.rs @@ -84,6 +84,11 @@ fn main() { primitive_arg(1u32); enum_arg(NotATuple::A(1u32)); + #[rustfmt::skip] + let primitive_arg_: fn(#[rustc_splat] u32) = primitive_arg; + primitive_arg_(1u32); + //~^ ERROR cannot use `rustc_splat` attribute; the splatted argument type must be a tuple or unit, not a u32 + let foo = Foo; struct_arg(foo); foo.tuple_2_self((1u32, 2i8)); diff --git a/tests/ui/splat/splat-non-tuple.stderr b/tests/ui/splat/splat-non-tuple.stderr index d51968eac80c0..b92c257b9b021 100644 --- a/tests/ui/splat/splat-non-tuple.stderr +++ b/tests/ui/splat/splat-non-tuple.stderr @@ -30,6 +30,12 @@ LL | fn enum_arg(#[rustc_splat] y: NotATuple) {} LL | enum_arg(NotATuple::A(1u32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0277]: cannot use `rustc_splat` attribute; the splatted argument type must be a tuple or unit, not a u32 (u32) + --> $DIR/splat-non-tuple.rs:89:5 + | +LL | primitive_arg_(1u32); + | ^^^^^^^^^^^^^^^^^^^^ + error[E0277]: cannot use `rustc_splat` attribute; the splatted argument type must be a tuple or unit, not a Foo (Foo) --> $DIR/splat-non-tuple.rs:25:33 | @@ -48,7 +54,7 @@ LL | fn tuple_struct_arg(#[rustc_splat] z: TupleStruct) {} LL | tuple_struct_arg(tuple_struct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0053, E0277. For more information about an error, try `rustc --explain E0053`. From 26783329db38698ece2975c73f31fe128e2588ef Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez Date: Tue, 25 Aug 2026 23:42:24 +0200 Subject: [PATCH 14/40] Make `tcx.def_id_partial_cmp` public This is mainly because it would be very useful in Clippy to have a fast way to check if two DefIds are related (and what that relation is). --- compiler/rustc_middle/src/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 19d86ebe7cced..b98e633069ef4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -504,7 +504,7 @@ impl TyCtxt<'_> { /// Compare def-ids based on their position in def-id tree, ancestor def-ids are considered /// larger than descendant def-ids, and two different def-ids are considered unordered if /// neither of them is an ancestor of the other. - fn def_id_partial_cmp(self, lhs: DefId, rhs: DefId) -> Option { + pub fn def_id_partial_cmp(self, lhs: DefId, rhs: DefId) -> Option { // Def-ids from different crates are always unordered. if lhs.krate != rhs.krate { return None; From 3e5c0fa819f1e07f7ce7738b8826f67f741d8ac3 Mon Sep 17 00:00:00 2001 From: Philip Kannegaard Hayes Date: Thu, 27 Aug 2026 14:38:31 -0700 Subject: [PATCH 15/40] std::sys::pal::sgx: fix mismatched alloc/free alignment `User::new_uninit_bytes` and `User::drop` are asking the host to alloc/dealloc memory with potentially mismatched alignment, as the enclave side is unconditionally over-aligning on allocation but not doing the same on free. - Ex: `User::` -> `alloc(_, align=8)` -> `drop()` -> `free(_, align=1)` For most hosts running stock x86_64-linux + glibc malloc, I don't believe this mismatch is an issue, since posix `free` ignores the alignment anyway. My guess is that if you're using jemalloc, which does care about the dealloc alignment, then something _might_ go wrong. It's also not clear that we can just round-up the alignment on `free`, since `User::from_raw` exists, and there's various places that call it outside std. We should probably just remove the min. alignment until we come up with a more satisfactory solution. My guess is that the right place to do the min. alignment optimization is in the host-side enclave-runner: and other places that hand memory to the SGX enclave. NB. The min. alignment exists for performance reasons (see: `copy_from_userspace`). It's highly preferable if all memory copied from userspace is at least 8 byte aligned, otherwise we have to fallback to a super slow copy routine for the unaligned prefix (and suffix). --- library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index f4115ca6124a7..1b89746682f3a 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -253,11 +253,9 @@ where unsafe { // Mustn't call alloc with size 0. let ptr = if size > 0 { - // `copy_to_userspace` is more efficient when data is 8-byte aligned - let alignment = cmp::max(T::align_of(), 8); - rtunwrap!(Ok, super::alloc(size, alignment)) as _ + rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ } else { - T::align_of() as _ // dangling pointer ok for size 0 + crate::ptr::dangling() // dangling pointer ok for size 0 }; if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) { User(NonNull::new_userref(v)) From 868bc2a074a24d44adb8e2858219cd71a2ad522d Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Fri, 28 Aug 2026 22:47:24 +0000 Subject: [PATCH 16/40] sanitizers: Implicitly disable mutually exclusive sanitizers This attempts to match clang's behavior of implicitly disabling sanitizers that are incompatible. Specifically, if a set of default sanitizers would be incompatible with ones provided by -Zsanitize=..., then clang (and now rust) will opt for keeping the ones specified via flags over the ones used as platform defaults. This helps maintain build consistency where we can just enable sanitizers via flags for both rust and c++ code without needing to manually disable others. The driving reason for this is asan and safestack where we'd like to enable safestack by default for x86_64 fuchsia but disable it if -Zsanitize=address is passed (matching clang's behavior). This commit also refactors all uses of `self.opts.unstable_opts.sanitizer` to go through the updated `sanitizer()` method. AI: Gemini was used to help review the code and write some tests, but it did not generate the whole patch. I edited and reviewed this PR to the best of my ability before pushing for review. --- compiler/rustc_session/src/options.rs | 6 ++-- compiler/rustc_session/src/session.rs | 16 ++++----- compiler/rustc_structures/src/lib.rs | 3 ++ .../rustc_structures/src/sanitizer_set.rs | 14 ++++++++ compiler/rustc_structures/src/tests.rs | 36 +++++++++++++++++++ 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_structures/src/tests.rs diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 90459090ced87..e72eeab63a590 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -95,13 +95,15 @@ mod target_modifier_consistency_check { l: &TargetModifier, r: Option<&TargetModifier>, ) -> bool { - let mut lparsed: SanitizerSet = sess.target.options.default_sanitizers; + let mut lparsed: SanitizerSet = SanitizerSet::empty(); let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) }; parse::parse_sanitizers(&mut lparsed, lval); + let lparsed = lparsed.combine_with_defaults(sess.target.options.default_sanitizers); - let mut rparsed: SanitizerSet = sess.target.options.default_sanitizers; + let mut rparsed: SanitizerSet = SanitizerSet::empty(); let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str()); parse::parse_sanitizers(&mut rparsed, rval); + let rparsed = rparsed.combine_with_defaults(sess.target.options.default_sanitizers); // Some sanitizers need to be target modifiers, and some do not. // For now, we should mark all sanitizers as target modifiers except for these: diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f04f40dd17168..dad43f94a57db 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -929,7 +929,7 @@ impl Session { let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) || self.opts.output_types.contains_key(&OutputType::Bitcode) // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. - || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); + || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); !more_names } } @@ -1178,7 +1178,10 @@ impl Session { } pub fn sanitizers(&self) -> SanitizerSet { - return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers; + self.opts + .unstable_opts + .sanitizer + .combine_with_defaults(self.target.options.default_sanitizers) } pub fn pointer_authentication(&self) -> bool { @@ -1497,7 +1500,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Sanitizers can only be used on platforms that we know have working sanitizer codegen. let supported_sanitizers = sess.target.options.supported_sanitizers; - let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers; + let mut unsupported_sanitizers = sess.sanitizers() - supported_sanitizers; // Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled // we should allow Shadow Call Stack sanitizer. if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == Arch::AArch64 { @@ -1518,7 +1521,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // Cannot mix and match mutually-exclusive sanitizers. - if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() { + if let Some((first, second)) = sess.sanitizers().mutually_exclusive() { sess.dcx().emit_err(diagnostics::CannotMixAndMatchSanitizers { first: first.to_string(), second: second.to_string(), @@ -1526,10 +1529,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // Cannot enable crt-static with sanitizers on Linux - if sess.crt_static(None) - && !sess.opts.unstable_opts.sanitizer.is_empty() - && !sess.target.is_like_msvc - { + if sess.crt_static(None) && !sess.sanitizers().is_empty() && !sess.target.is_like_msvc { sess.dcx().emit_err(diagnostics::CannotEnableCrtStaticLinux); } diff --git a/compiler/rustc_structures/src/lib.rs b/compiler/rustc_structures/src/lib.rs index a7ebea5ba9943..cb5dccdfcd180 100644 --- a/compiler/rustc_structures/src/lib.rs +++ b/compiler/rustc_structures/src/lib.rs @@ -13,3 +13,6 @@ pub use crate_type::CrateType; pub use limit::Limit; pub use native_lib_kind::NativeLibKind; pub use sanitizer_set::SanitizerSet; + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_structures/src/sanitizer_set.rs b/compiler/rustc_structures/src/sanitizer_set.rs index bce77f3abc05b..a41577441de8c 100644 --- a/compiler/rustc_structures/src/sanitizer_set.rs +++ b/compiler/rustc_structures/src/sanitizer_set.rs @@ -95,6 +95,20 @@ impl SanitizerSet { .find(|&(a, b)| self.contains(*a) && self.contains(*b)) .copied() } + + /// Disable default sanitizers that are incompatible with explicitly requested ones, + /// matching Clang's `SanitizerArgs` driver logic. + pub fn combine_with_defaults(self, mut defaults: SanitizerSet) -> SanitizerSet { + for &(a, b) in Self::MUTUALLY_EXCLUSIVE { + if defaults.contains(a) && self.contains(b) { + defaults -= a; + } + if defaults.contains(b) && self.contains(a) { + defaults -= b; + } + } + self | defaults + } } /// Formats a sanitizer set as a comma separated list of sanitizers' names. diff --git a/compiler/rustc_structures/src/tests.rs b/compiler/rustc_structures/src/tests.rs new file mode 100644 index 0000000000000..3d61d5bf3331f --- /dev/null +++ b/compiler/rustc_structures/src/tests.rs @@ -0,0 +1,36 @@ +use super::*; + +#[test] +fn test_combine_with_defaults_no_conflict() { + let defaults = SanitizerSet::SHADOWCALLSTACK; + let explicit = SanitizerSet::ADDRESS; + assert_eq!( + explicit.combine_with_defaults(defaults), + SanitizerSet::ADDRESS | SanitizerSet::SHADOWCALLSTACK + ); +} + +#[test] +fn test_combine_with_defaults_safestack_address_conflict() { + let defaults = SanitizerSet::SAFESTACK; + let explicit = SanitizerSet::ADDRESS; + // SafeStack should be implicitly disabled when Address is explicitly provided. + assert_eq!(explicit.combine_with_defaults(defaults), SanitizerSet::ADDRESS); +} + +#[test] +fn test_combine_with_defaults_empty_explicit() { + let defaults = SanitizerSet::SAFESTACK; + let explicit = SanitizerSet::empty(); + assert_eq!(explicit.combine_with_defaults(defaults), SanitizerSet::SAFESTACK); +} + +#[test] +fn test_combine_with_defaults_safestack_cfi() { + let defaults = SanitizerSet::SAFESTACK; + let explicit = SanitizerSet::CFI; + assert_eq!( + explicit.combine_with_defaults(defaults), + SanitizerSet::CFI | SanitizerSet::SAFESTACK + ); +} From 3519ad59ae70e657b7f0175254705e282f8b2df4 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Fri, 10 Jul 2026 12:01:47 +0000 Subject: [PATCH 17/40] [PAC] Include discriminator in `FnAbi`, add `llvm.ptrauth.resign` This patch introduces the following: * Extends `FnAbi` (`callconv`) with a `ptrauth_type_discriminator` field. This field is only used when emitting pointer authentication call bundles. It is stored in `FnAbi` because the call site is not guaranteed to have access to an `Instance`, so the discriminator cannot always be computed on demand. * Adds support for `llvm.ptrauth.resign`. This intrinsic will be used when support for semantic transmute is added. * Performs a minor API redesign as groundwork for allowing call sites to modify schemas in place. --- compiler/rustc_codegen_gcc/src/builder.rs | 11 +++++++ compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_gcc/src/context.rs | 2 +- compiler/rustc_codegen_gcc/src/int.rs | 1 + compiler/rustc_codegen_llvm/src/builder.rs | 32 +++++++++++++++++-- compiler/rustc_codegen_llvm/src/common.rs | 23 +++++++------ compiler/rustc_codegen_llvm/src/context.rs | 4 +-- .../rustc_codegen_ssa/src/traits/builder.rs | 9 ++++++ .../rustc_codegen_ssa/src/traits/consts.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/misc.rs | 2 +- compiler/rustc_session/src/session.rs | 25 ++++++++++++--- compiler/rustc_target/src/callconv/mod.rs | 8 +++-- compiler/rustc_ty_utils/src/abi.rs | 6 ++++ tests/ui/abi/c-zst.aarch64-darwin.stderr | 1 + tests/ui/abi/c-zst.powerpc-linux.stderr | 1 + tests/ui/abi/c-zst.s390x-linux.stderr | 1 + tests/ui/abi/c-zst.sparc64-linux.stderr | 1 + tests/ui/abi/c-zst.x86_64-linux.stderr | 1 + .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 1 + tests/ui/abi/debug.generic.stderr | 12 +++++++ tests/ui/abi/debug.loongarch64.stderr | 12 +++++++ tests/ui/abi/debug.riscv64.stderr | 12 +++++++ .../x86-64-sysv64-arg-ext.apple.stderr | 6 ++++ .../x86-64-sysv64-arg-ext.other.stderr | 6 ++++ tests/ui/abi/pass-indirectly-attr.stderr | 2 ++ tests/ui/abi/sysv64-zst.stderr | 1 + .../pass-by-value-abi.aarch64.stderr | 1 + .../c-variadic/pass-by-value-abi.win.stderr | 1 + .../pass-by-value-abi.x86_64.stderr | 3 ++ 29 files changed, 165 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 88049d67964b1..d42438ba92f59 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1850,6 +1850,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { self.fptoint_sat(true, val, dest_ty) } + + fn ptrauth_resign( + &mut self, + _value: Self::Value, + _old_key: u32, + _old_discriminator: u64, + _new_key: u32, + _new_discriminator: u64, + ) -> Self::Value { + bug!("Resigning of pointers not implemented"); + } } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 6bd186f1121fc..712a1c14ef8e6 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -323,7 +323,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>, - _schema: Option<&PointerAuthSchema>, + _ptrauth_schema: Option, ) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 19fbe37c27b9e..8c1fc18ee7a78 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -405,7 +405,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn get_fn_addr( &self, instance: Instance<'tcx>, - _pointer_auth_schema: Option<&PointerAuthSchema>, + _ptrauth_schema: Option, ) -> RValue<'gcc> { let func_name = self.tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index dfae4eceebe44..10cbe1ccb8059 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -375,6 +375,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fixed_count: 3, conv: CanonAbi::C, can_unwind: false, + ptrauth_discriminator: 0, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 87c941cdeb23a..63e6faf3ced93 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1553,6 +1553,30 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let cold_inline = llvm::AttributeKind::Cold.create_attr(self.llcx); attributes::apply_to_callsite(llret, llvm::AttributePlace::Function, &[cold_inline]); } + + fn ptrauth_resign( + &mut self, + value: &'ll Value, + old_key: u32, + old_discriminator: u64, + new_key: u32, + new_discriminator: u64, + ) -> &'ll Value { + let ptr_as_int = self.ptrtoint(value, self.type_i64()); + let resigned_int = self.call_intrinsic( + "llvm.ptrauth.resign", + &[], + &[ + ptr_as_int, + self.const_i32(old_key as i32), + self.const_i64(old_discriminator as i64), + self.const_i32(new_key as i32), + self.const_i64(new_discriminator as i64), + ], + ); + + self.inttoptr(resigned_int, self.val_ty(value)) + } } impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { @@ -2171,8 +2195,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // bundles. // Once this is resolved, we should analyze each call and skip direct calls. See the // discussion in the rust-lang issue: - let key: u32 = 0; - let discriminator: u64 = 0; + + let key: u32 = self.sess().pointer_authentication_fn_ptr_key().unwrap() as u32; + // If sess().pointer_authentication_fn_ptr_type_discrimination() is true, this contains + // the function pointer type discriminator; otherwise, it is 0. + let discriminator = fn_abi?.ptrauth_discriminator; + Some(llvm::OperandBundleBox::new( "ptrauth", &[self.const_u32(key), self.const_u64(discriminator)], diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 3fe4550b6759e..8f63e409028ce 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -30,11 +30,9 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( cx: &CodegenCx<'ll, '_>, instance: Instance<'tcx>, llfn: &'ll llvm::Value, - schema: &PointerAuthSchema, + ptrauth_schema: PointerAuthSchema, ) -> &'ll llvm::Value { - if cx.tcx.sess.pointer_authentication_functions().is_none() { - return llfn; - } + assert!(cx.tcx.sess.pointer_authentication_functions().is_some()); // Only free functions or methods let def_id = instance.def_id(); @@ -54,7 +52,7 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( return llfn; } - let addr_diversity = match schema.is_address_discriminated { + let addr_diversity = match ptrauth_schema.is_address_discriminated { PointerAuthAddressDiscriminator::HardwareAddress(true) => Some(llfn), PointerAuthAddressDiscriminator::HardwareAddress(false) => None, PointerAuthAddressDiscriminator::Synthetic(val) => { @@ -63,7 +61,12 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) }) } }; - const_ptr_auth(llfn, schema.key as u32, schema.constant_discriminator as u64, addr_diversity) + const_ptr_auth( + llfn, + ptrauth_schema.key as u32, + ptrauth_schema.constant_discriminator as u64, + addr_diversity, + ) } /* @@ -179,11 +182,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { &self, global_alloc: GlobalAlloc<'tcx>, need_symbol_name: bool, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Result<&'ll Value, u64> { let alloc = match global_alloc { GlobalAlloc::Function { instance, .. } => { - return Ok(self.get_fn_addr(instance, schema)); + return Ok(self.get_fn_addr(instance, ptrauth_schema)); } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); @@ -405,7 +408,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { cv: Scalar, layout: abi::Scalar, llty: &'ll Type, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { @@ -422,7 +425,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr_space = global_alloc.address_space(self); - let base_addr = match self.alloc_to_backend(global_alloc, false, schema) { + let base_addr = match self.alloc_to_backend(global_alloc, false, ptrauth_schema) { Ok(base_addr) => base_addr, Err(base_addr) => { let val = base_addr.wrapping_add(offset.bytes()); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 853c4bfc9ca3f..c136fb6bbde8a 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -938,7 +938,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn get_fn_addr( &self, instance: Instance<'tcx>, - pointer_auth_schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> &'ll Value { // When pointer authentication metadata is provided, `get_fn_addr` will // attempt to sign the pointer using LLVM's `ConstPtrAuth` constant @@ -953,7 +953,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { // , and comment in // builder's `ptrauth_operand_bundle`. let llfn = get_fn(self, instance); - match pointer_auth_schema { + match ptrauth_schema { Some(schema) => common::maybe_sign_fn_ptr(self, instance, llfn, schema), None => llfn, } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index cb0209a0ae369..0e37705ec82b5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -667,4 +667,13 @@ pub trait BuilderMethods<'a, 'tcx>: fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); + + fn ptrauth_resign( + &mut self, + value: Self::Value, + old_key: u32, + old_discriminator: u64, + new_key: u32, + new_discriminator: u64, + ) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index b4eba38d39c19..b45b5667be6c9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -47,7 +47,7 @@ pub trait ConstCodegenMethods: BackendTypes { cv: Scalar, layout: abi::Scalar, llty: Self::Type, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index add7128a2974b..3d1a931a12e83 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -22,7 +22,7 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes { fn get_fn_addr( &self, instance: Instance<'tcx>, - pointer_auth_schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Self::Value; fn eh_personality(&self) -> Self::Function; fn sess(&self) -> &Session; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f04f40dd17168..e31176a88acee 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -95,6 +95,7 @@ pub enum PointerAuthARM8_3Key { } /// Forms of extra discrimination. +#[derive(Clone, Debug, PartialEq)] pub enum PointerAuthDiscrimination { /// No additional discrimination. None, @@ -107,6 +108,7 @@ pub enum PointerAuthDiscrimination { } /// Types of address discrimination. +#[derive(Clone, Debug)] pub enum PointerAuthAddressDiscriminator { /// Enable/disable hardware address discrimination. HardwareAddress(bool), @@ -115,6 +117,7 @@ pub enum PointerAuthAddressDiscriminator { Synthetic(u64), } +#[derive(Clone, Debug)] pub struct PointerAuthSchema { pub is_address_discriminated: PointerAuthAddressDiscriminator, pub discrimination_kind: PointerAuthDiscrimination, @@ -1185,12 +1188,26 @@ impl Session { self.pointer_auth_config.is_some() } - pub fn pointer_authentication_functions(&self) -> Option<&PointerAuthSchema> { - self.pointer_auth_config.as_ref().and_then(|cfg| cfg.function_pointers.as_ref()) + pub fn pointer_authentication_functions(&self) -> Option { + self.pointer_auth_config.as_ref().and_then(|cfg| cfg.function_pointers.clone()) } - pub fn pointer_authentication_init_fini(&self) -> Option<&PointerAuthSchema> { - self.pointer_auth_config.as_ref().and_then(|cfg| cfg.init_fini.as_ref()) + pub fn pointer_authentication_init_fini(&self) -> Option { + self.pointer_auth_config.as_ref().and_then(|cfg| cfg.init_fini.clone()) + } + + pub fn pointer_authentication_fn_ptr_type_discrimination(&self) -> bool { + self.pointer_auth_config + .as_ref() + .and_then(|cfg| cfg.function_pointers.as_ref()) + .is_some_and(|schema| schema.discrimination_kind == PointerAuthDiscrimination::Type) + } + + pub fn pointer_authentication_fn_ptr_key(&self) -> Option { + self.pointer_auth_config + .as_ref() + .and_then(|cfg| cfg.function_pointers.as_ref()) + .map(|schema| schema.key) } } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 26fedbd8a5481..83f38b5be8a9b 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -625,12 +625,15 @@ pub struct FnAbi<'a, Ty> { pub conv: CanonAbi, /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, + /// Computed type discriminator for pointer authentication purpose. + pub ptrauth_discriminator: u64, } // Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind } = self; + let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind, ptrauth_discriminator } = + self; f.debug_struct("FnAbi") .field("args", args) .field("ret", ret) @@ -638,6 +641,7 @@ impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { .field("fixed_count", fixed_count) .field("conv", conv) .field("can_unwind", can_unwind) + .field("ptrauth_discriminator", ptrauth_discriminator) .finish() } } @@ -950,6 +954,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(ArgAbi<'_, usize>, 56); - static_assert_size!(FnAbi<'_, usize>, 80); + static_assert_size!(FnAbi<'_, usize>, 88); // tidy-alphabetical-end } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 65d589cc35aa0..2b59c905b19f5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -6,6 +6,7 @@ use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::{self as hir, find_attr}; use rustc_middle::bug; use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs; +use rustc_middle::ptrauth::ptrauth_compute_fn_ptr_type_discriminator_for; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, @@ -611,6 +612,11 @@ fn fn_abi_new_uncached<'tcx>( determined_fn_def_id, sig.abi(), ), + ptrauth_discriminator: if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { + ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into() + } else { + 0 + }, }; fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi()); debug!("fn_abi_new_uncached = {:?}", fn_abi); diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 6d2ac90c0c975..a99eb7cd1e830 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -59,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index edea2d5772280..308d3a8625638 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index edea2d5772280..308d3a8625638 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index edea2d5772280..308d3a8625638 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 6d2ac90c0c975..a99eb7cd1e830 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -59,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index edea2d5772280..308d3a8625638 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 6242d93b09534..ae0edfd7369a2 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -481,6 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -554,6 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -626,6 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -692,6 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -764,6 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -830,6 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -924,6 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index 176c68ecd4c7b..ed20ec1ef3283 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -481,6 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -554,6 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -626,6 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -692,6 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -764,6 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -830,6 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -924,6 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index 176c68ecd4c7b..ed20ec1ef3283 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -481,6 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -554,6 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -626,6 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -692,6 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -764,6 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -830,6 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -924,6 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr index 65818feab4297..927594534d9b8 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr @@ -69,6 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -146,6 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -223,6 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -300,6 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -377,6 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -454,6 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr index cbe389c42d40a..113ad20e16bc4 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr @@ -69,6 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -146,6 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -223,6 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -300,6 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -377,6 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -454,6 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index efeec0d86982b..e03828c2e78a4 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -83,6 +83,7 @@ error: fn_abi_of(extern_c) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-indirectly-attr.rs:20:1 | @@ -174,6 +175,7 @@ error: fn_abi_of(extern_rust) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-indirectly-attr.rs:27:1 | diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 82d3793c35328..ed8fe5b83fe7c 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -61,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/sysv64-zst.rs:8:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index 45edd7bc0e0ee..7f25ffc3c4481 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr index d5da912a9b89a..150a9262b0f88 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.win.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -66,6 +66,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 1e203b93e66b3..1705d3ca7509b 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -70,6 +70,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | @@ -150,6 +151,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:37:1 | @@ -230,6 +232,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { Win64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:44:1 | From 1846500cbc24252a6678ba48452086707c9a0599 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Thu, 20 Aug 2026 06:47:34 +0000 Subject: [PATCH 18/40] [PAC] Use Option in FnAbi's discriminator field --- compiler/rustc_codegen_gcc/src/int.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 7 +++--- compiler/rustc_target/src/callconv/mod.rs | 4 ++-- compiler/rustc_ty_utils/src/abi.rs | 4 ++-- tests/ui/abi/c-zst.aarch64-darwin.stderr | 2 +- tests/ui/abi/c-zst.powerpc-linux.stderr | 2 +- tests/ui/abi/c-zst.s390x-linux.stderr | 2 +- tests/ui/abi/c-zst.sparc64-linux.stderr | 2 +- tests/ui/abi/c-zst.x86_64-linux.stderr | 2 +- .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 2 +- tests/ui/abi/debug.generic.stderr | 24 +++++++++---------- tests/ui/abi/debug.loongarch64.stderr | 24 +++++++++---------- tests/ui/abi/debug.riscv64.stderr | 24 +++++++++---------- .../x86-64-sysv64-arg-ext.apple.stderr | 12 +++++----- .../x86-64-sysv64-arg-ext.other.stderr | 12 +++++----- tests/ui/abi/pass-indirectly-attr.stderr | 4 ++-- tests/ui/abi/sysv64-zst.stderr | 2 +- .../pass-by-value-abi.aarch64.stderr | 2 +- .../c-variadic/pass-by-value-abi.win.stderr | 2 +- .../pass-by-value-abi.x86_64.stderr | 6 ++--- 20 files changed, 71 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 10cbe1ccb8059..fe0654c665c76 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -375,7 +375,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fixed_count: 3, conv: CanonAbi::C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 63e6faf3ced93..63563bad966d9 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2197,9 +2197,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // discussion in the rust-lang issue: let key: u32 = self.sess().pointer_authentication_fn_ptr_key().unwrap() as u32; - // If sess().pointer_authentication_fn_ptr_type_discrimination() is true, this contains - // the function pointer type discriminator; otherwise, it is 0. - let discriminator = fn_abi?.ptrauth_discriminator; + // If sess().pointer_authentication_fn_ptr_type_discrimination() is enabled, this contains + // the function pointer type discriminator; otherwise, it is None. LLVM expects a u64 here, + // so use 0 when no discriminator is present. + let discriminator = fn_abi?.ptrauth_discriminator.unwrap_or(0); Some(llvm::OperandBundleBox::new( "ptrauth", diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 83f38b5be8a9b..14ad0eb477d5d 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -626,7 +626,7 @@ pub struct FnAbi<'a, Ty> { /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, /// Computed type discriminator for pointer authentication purpose. - pub ptrauth_discriminator: u64, + pub ptrauth_discriminator: Option, } // Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. @@ -954,6 +954,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(ArgAbi<'_, usize>, 56); - static_assert_size!(FnAbi<'_, usize>, 88); + static_assert_size!(FnAbi<'_, usize>, 96); // tidy-alphabetical-end } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2b59c905b19f5..318b3273219a5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -613,9 +613,9 @@ fn fn_abi_new_uncached<'tcx>( sig.abi(), ), ptrauth_discriminator: if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { - ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into() + Some(ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into()) } else { - 0 + None }, }; fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi()); diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index a99eb7cd1e830..e7cb6199ab45c 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -59,7 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index 308d3a8625638..437ebd63ceba5 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index 308d3a8625638..437ebd63ceba5 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index 308d3a8625638..437ebd63ceba5 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index a99eb7cd1e830..e7cb6199ab45c 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -59,7 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index 308d3a8625638..437ebd63ceba5 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:65:1 | diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index ae0edfd7369a2..82c469e0f4f80 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -486,7 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -560,7 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -633,7 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -700,7 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -773,7 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -840,7 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -935,7 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index ed20ec1ef3283..b5c73d00564c6 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -486,7 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -560,7 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -633,7 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -700,7 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -773,7 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -840,7 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -935,7 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index ed20ec1ef3283..b5c73d00564c6 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -486,7 +486,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -560,7 +560,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -633,7 +633,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -700,7 +700,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -773,7 +773,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -840,7 +840,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -935,7 +935,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr index 927594534d9b8..df49fbfe3d272 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr @@ -69,7 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -147,7 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -225,7 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -303,7 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -381,7 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -459,7 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr index 113ad20e16bc4..7ceb6a2092af2 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr @@ -69,7 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -147,7 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -225,7 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -303,7 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -381,7 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -459,7 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index e03828c2e78a4..935ab97647321 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -83,7 +83,7 @@ error: fn_abi_of(extern_c) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-indirectly-attr.rs:20:1 | @@ -175,7 +175,7 @@ error: fn_abi_of(extern_rust) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-indirectly-attr.rs:27:1 | diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index ed8fe5b83fe7c..f19480faec4fa 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -61,7 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/sysv64-zst.rs:8:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index 7f25ffc3c4481..c616e45a9ab8e 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr index 150a9262b0f88..638a0856b7b7f 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.win.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -66,7 +66,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 1705d3ca7509b..776d0a72287f9 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -70,7 +70,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | @@ -151,7 +151,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:37:1 | @@ -232,7 +232,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { Win64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:44:1 | From 8f316d411dc9fc3c25aa9e0745cf4d3c252ae592 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 3 Sep 2026 12:42:20 +0200 Subject: [PATCH 19/40] refactor `rustc_allowed_through_unstable_modules` attribute and lint message --- compiler/rustc_attr_ir/src/stability.rs | 5 +- .../src/attributes/stability.rs | 54 +++++-- .../rustc_attr_parsing/src/diagnostics.rs | 9 ++ .../src/error_codes/E0789.md | 5 +- compiler/rustc_middle/src/middle/stability.rs | 4 +- compiler/rustc_passes/src/diagnostics.rs | 17 +++ compiler/rustc_passes/src/stability.rs | 36 ++--- library/core/src/intrinsics/mod.rs | 20 ++- src/librustdoc/clean/types.rs | 4 +- .../fully-stable-path-is-better.rs | 4 +- tests/rustdoc-html/stability.rs | 5 +- tests/ui/error-codes/E0789.rs | 2 +- .../accidental-stable-in-unstable.stderr | 11 +- .../accidentally-stable-intrinsics.fixed | 39 +++++ .../accidentally-stable-intrinsics.rs | 39 +++++ .../accidentally-stable-intrinsics.stderr | 139 ++++++++++++++++++ .../allowed-through-unstable.rs | 4 +- .../allowed-through-unstable.stderr | 11 +- .../allowed-through-unstable-core.rs | 5 +- 19 files changed, 360 insertions(+), 53 deletions(-) create mode 100644 tests/ui/stability-attribute/accidentally-stable-intrinsics.fixed create mode 100644 tests/ui/stability-attribute/accidentally-stable-intrinsics.rs create mode 100644 tests/ui/stability-attribute/accidentally-stable-intrinsics.stderr diff --git a/compiler/rustc_attr_ir/src/stability.rs b/compiler/rustc_attr_ir/src/stability.rs index 1cba0b59c0f6c..8d0551e92472d 100644 --- a/compiler/rustc_attr_ir/src/stability.rs +++ b/compiler/rustc_attr_ir/src/stability.rs @@ -139,8 +139,9 @@ pub enum StabilityLevel { /// Rust release which stabilized this feature. since: StableSince, /// This is `Some` if this item allowed to be referred to on stable via unstable modules; - /// the `Symbol` is the deprecation message printed in that case. - allowed_through_unstable_modules: Option, + /// the first `Symbol` is the deprecation message printed in that case, + /// the second `Symbol` is the correct module to use. + allowed_through_unstable_modules: Option<(Symbol, Symbol)>, }, } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6dbbe0bf4d0c8..29e288d858c37 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -10,6 +10,7 @@ use rustc_feature::{ACCEPTED_LANG_FEATURES, AttributeStability}; use super::prelude::*; use super::util::parse_version; +use crate::context::ExpectNameValue; use crate::diagnostics; const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ @@ -49,7 +50,7 @@ const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ #[derive(Default)] pub(crate) struct StabilityParser { - allowed_through_unstable_modules: Option, + allowed_through_unstable_modules: Option<(Symbol, Symbol)>, stability: Option<(Stability, Span)>, } @@ -93,16 +94,51 @@ impl AttributeParser for StabilityParser { ), ( &[sym::rustc_allowed_through_unstable_modules], - template!(NameValueStr: "deprecation message"), + template!(List: &[r#"message = "...", module = "..."#]), unstable!(staged_api), |this, cx, args| { - let Some(nv) = cx.expect_name_value(args, cx.attr_span, None) else { - return; - }; - let Some(value_str) = cx.expect_string_literal(nv) else { - return; - }; - this.allowed_through_unstable_modules = Some(value_str); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return }; + let mut message = None; + let mut module = None; + + for item in list.mixed() { + let Some((name, value)) = item.expect_name_value(cx, item.span(), None) else { + return; + }; + let Some(value) = cx.expect_string_literal(value) else { + return; + }; + + match name.name { + sym::message => { + if message.is_some() { + cx.adcx().duplicate_key(name.span, name.name); + } else { + message = Some(value) + } + } + sym::module => { + if module.is_some() { + cx.adcx().duplicate_key(name.span, name.name); + } else { + module = Some(value) + } + } + _ => { + cx.adcx().expected_specific_argument( + name.span, + &[sym::message, sym::module], + ); + } + } + } + + let allowed_through_unstable_modules = try { (message?, module?) }; + if allowed_through_unstable_modules.is_none() { + cx.emit_err(diagnostics::RustcAtumMissingParams { span: cx.attr_span }); + } + + this.allowed_through_unstable_modules = allowed_through_unstable_modules; }, ), ]; diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index a37d56419adac..663915e39dccd 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1136,6 +1136,15 @@ pub(crate) struct RustcAllowedUnstablePairing { pub span: Span, } +#[derive(Diagnostic)] +#[diag( + "`rustc_allowed_through_unstable_modules` attribute must have `message` and `module` params" +)] +pub(crate) struct RustcAtumMissingParams { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("suggestions on deprecated items are unstable")] pub(crate) struct DeprecatedItemSuggestion { diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md index c7bc6cfde5134..6cf0c7243d854 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0789.md +++ b/compiler/rustc_error_codes/src/error_codes/E0789.md @@ -14,7 +14,10 @@ Erroneous code example: #![unstable(feature = "foo_module", reason = "...", issue = "123")] -#[rustc_allowed_through_unstable_modules = "deprecation message"] +#[rustc_allowed_through_unstable_modules( + message = "deprecation message", + module = "stable_module", +)] // #[stable(feature = "foo", since = "1.0")] struct Foo; // ^^^ error: `rustc_allowed_through_unstable_modules` attribute must be diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 51f75367f11cf..099697c68464c 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -102,7 +102,7 @@ fn deprecation_lint(is_in_effect: bool) -> &'static Lint { style = "verbose", applicability = "machine-applicable" )] -pub struct DeprecationSuggestion { +pub(crate) struct DeprecationSuggestion { #[primary_span] pub span: Span, @@ -110,7 +110,7 @@ pub struct DeprecationSuggestion { pub suggestion: Symbol, } -pub struct Deprecated { +pub(crate) struct Deprecated { pub sub: Option, pub kind: String, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index c343d9c7078e7..5c2ba5b33f11f 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -1164,3 +1164,20 @@ pub(crate) struct ConstFnLinkage { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag("use of deprecated import through accidentally stabilized module `{$module}`")] +pub(crate) struct RustcAtumSuggestion { + #[primary_span] + pub import_span: Span, + pub message: Symbol, + pub suggestion: Symbol, + pub module: Ident, + #[suggestion( + "{$message}", + code = "{suggestion}", + style = "verbose", + applicability = "machine-applicable" + )] + pub unstable_mod_span: Span, +} diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 37ec1dc01bd4b..d88675d4fa36a 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,16 +16,15 @@ use rustc_hir::{ ItemKind, Path, Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason, UsePath, VERSION_PLACEHOLDER, Variant, find_attr, }; -use rustc_lint_defs as lint; use rustc_lint_defs::builtin::{ DEPRECATED, DUPLICATE_FEATURES, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, STABLE_FEATURES, }; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult}; +use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, EvalResult}; use rustc_middle::query::{LocalCrate, Providers}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::span_bug; use rustc_middle::ty::{AssocContainer, TyCtxt}; use rustc_span::{Span, Symbol, sym}; use tracing::instrument; @@ -790,7 +789,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { if item_is_allowed { // The item itself is allowed; check whether the path there is also allowed. - let is_allowed_through_unstable_modules: Option = + let is_allowed_through_unstable_modules: Option<(Symbol, Symbol)> = self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level { StabilityLevel::Stable { allowed_through_unstable_modules, .. } => { allowed_through_unstable_modules @@ -829,7 +828,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { }, ); } - Some(deprecation) => { + Some((message, suggestion)) => { // Call the stability check directly so that we can control which // diagnostic is emitted. let eval_result = self.tcx.eval_stability_allow_unstable( @@ -845,22 +844,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { ); let is_allowed = matches!(eval_result, EvalResult::Allow); if !is_allowed { - // Calculating message for lint involves calling `self.def_path_str`, - // which will by default invoke the expensive `visible_parent_map` query. - // Skip all that work if the lint is allowed anyway. - if self.tcx.lint_level_spec_at_node(DEPRECATED, id).is_allow() { - return; - } // Show a deprecation message. - let def_path = - with_no_trimmed_paths!(self.tcx.def_path_str(def_id)); - let def_kind = self.tcx.def_descr(def_id); - let diag = Deprecated { - sub: None, - kind: def_kind.to_owned(), - path: def_path, - note: Some(deprecation), - since_kind: lint::DeprecatedSinceKind::InEffect, + let [.., intrinsics_module, _intrinsic] = path.segments else { + span_bug!( + path.span, + "no module for `is_allowed_through_unstable_modules` intrinsic {path:?}" + ) + }; + let diag = diagnostics::RustcAtumSuggestion { + message, + import_span: path.span, + unstable_mod_span: { intrinsics_module.ident.span }, + module: intrinsics_module.ident, + suggestion, }; self.tcx.emit_node_span_lint( DEPRECATED, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4e9187f7933b2..96861b057f5bf 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -859,7 +859,10 @@ pub const fn forget(_: T); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules( + message = "import this function via the `mem` module instead", + module = "mem" +)] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] #[rustc_nounwind] @@ -3296,7 +3299,10 @@ pub const fn ptr_metadata + PointeeSized, M>(ptr: // debug assertions; if you are writing compiler tests or code inside the standard library // that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] +#[rustc_allowed_through_unstable_modules( + message = "import this function via the `ptr` module instead", + module = "ptr" +)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[rustc_nounwind] #[rustc_intrinsic] @@ -3307,7 +3313,10 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us // debug assertions; if you are writing compiler tests or code inside the standard library // that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] +#[rustc_allowed_through_unstable_modules( + message = "import this function via the `ptr` module instead", + module = "ptr" +)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[rustc_nounwind] #[rustc_intrinsic] @@ -3318,7 +3327,10 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize); // debug assertions; if you are writing compiler tests or code inside the standard library // that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] +#[rustc_allowed_through_unstable_modules( + message = "import this function via the `ptr` module instead", + module = "ptr" +)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[rustc_nounwind] #[rustc_intrinsic] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 47b701e3c42d7..7a99ce8d39e9c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -451,7 +451,7 @@ impl Item { // were never supposed to work at all. let stab = self.stability(tcx)?; if let rustc_hir::StabilityLevel::Stable { - allowed_through_unstable_modules: Some(note), + allowed_through_unstable_modules: Some((note, _)), .. } = stab.level { @@ -2534,7 +2534,7 @@ mod size_asserts { static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); static_assert_size!(Item, 8); - static_assert_size!(ItemInner, 136); + static_assert_size!(ItemInner, 144); static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 32); static_assert_size!(Type, 32); diff --git a/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs index 41bf42d2e7aad..343e66cfc9666 100644 --- a/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs +++ b/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs @@ -16,10 +16,10 @@ pub mod stb1 { #[unstable(feature = "uns", issue = "135003")] pub mod uns { #[stable(since = "1.0", feature = "stb1")] - #[rustc_allowed_through_unstable_modules = "use stable path instead"] + #[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stb1")] pub struct Inside1; #[stable(since = "1.0", feature = "stb2")] - #[rustc_allowed_through_unstable_modules = "use stable path instead"] + #[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stb2")] pub struct Inside2; } diff --git a/tests/rustdoc-html/stability.rs b/tests/rustdoc-html/stability.rs index 4870c68dfe5e6..8df66a59d3c15 100644 --- a/tests/rustdoc-html/stability.rs +++ b/tests/rustdoc-html/stability.rs @@ -85,7 +85,10 @@ pub mod stable_later { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "use stable path instead"] +#[rustc_allowed_through_unstable_modules( + message = "use stable path instead", + module = "stable_module", +)] pub mod stable_earlier1 { //@ has stability/stable_earlier1/struct.StableInUnstable.html \ // '//div[@class="main-heading"]//span[@class="since"]' '1.0.0' diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs index 4a55e1743158d..3b83d88aa9eaf 100644 --- a/tests/ui/error-codes/E0789.rs +++ b/tests/ui/error-codes/E0789.rs @@ -4,7 +4,7 @@ #![feature(staged_api)] #![unstable(feature = "foo_module", reason = "...", issue = "123")] -#[rustc_allowed_through_unstable_modules = "use stable path instead"] +#[rustc_allowed_through_unstable_modules(message = "use stable path instead", module = "stable")] // #[stable(feature = "foo", since = "1.0")] struct Foo; //~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute diff --git a/tests/ui/stability-attribute/accidental-stable-in-unstable.stderr b/tests/ui/stability-attribute/accidental-stable-in-unstable.stderr index 16e3676aa6503..b0b1f78cb28b2 100644 --- a/tests/ui/stability-attribute/accidental-stable-in-unstable.stderr +++ b/tests/ui/stability-attribute/accidental-stable-in-unstable.stderr @@ -7,13 +7,18 @@ LL | use core::unicode::UNICODE_VERSION; = help: add `#![feature(unicode_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: use of deprecated module `std::intrinsics`: import this function via `std::mem` instead - --> $DIR/accidental-stable-in-unstable.rs:10:23 +warning: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidental-stable-in-unstable.rs:10:5 | LL | use core::intrinsics::transmute; // depended upon by rand_core - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(deprecated)]` on by default +help: import this function via the `mem` module instead + | +LL - use core::intrinsics::transmute; // depended upon by rand_core +LL + use core::mem::transmute; // depended upon by rand_core + | error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/stability-attribute/accidentally-stable-intrinsics.fixed b/tests/ui/stability-attribute/accidentally-stable-intrinsics.fixed new file mode 100644 index 0000000000000..41917c65f5215 --- /dev/null +++ b/tests/ui/stability-attribute/accidentally-stable-intrinsics.fixed @@ -0,0 +1,39 @@ +//@ run-rustfix +#![crate_type = "lib"] +#![allow(unnecessary_transmutes, unused_imports)] +#![deny(deprecated)] + +extern crate core; + +use std::mem::transmute as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use core::ptr::copy as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use std::ptr::copy_nonoverlapping as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use core::ptr::write_bytes as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + +use core::ptr::{ + copy as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + copy_nonoverlapping as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + write_bytes as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +}; + +pub fn what() { + unsafe { + let value = 42_u8; + let mut dst = 0; + let _ = std::mem::transmute::(value); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + core::ptr::copy(&value, &mut dst, 1); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + core::ptr::copy_nonoverlapping(&value, &mut dst, 1); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + std::ptr::write_bytes(&mut dst, value, 1) + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + } +} diff --git a/tests/ui/stability-attribute/accidentally-stable-intrinsics.rs b/tests/ui/stability-attribute/accidentally-stable-intrinsics.rs new file mode 100644 index 0000000000000..189927e9e8989 --- /dev/null +++ b/tests/ui/stability-attribute/accidentally-stable-intrinsics.rs @@ -0,0 +1,39 @@ +//@ run-rustfix +#![crate_type = "lib"] +#![allow(unnecessary_transmutes, unused_imports)] +#![deny(deprecated)] + +extern crate core; + +use std::intrinsics::transmute as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use core::intrinsics::copy as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use std::intrinsics::copy_nonoverlapping as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +use core::intrinsics::write_bytes as _; +//~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + +use core::intrinsics::{ + copy as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + copy_nonoverlapping as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + write_bytes as _, + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` +}; + +pub fn what() { + unsafe { + let value = 42_u8; + let mut dst = 0; + let _ = std::intrinsics::transmute::(value); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + core::intrinsics::copy(&value, &mut dst, 1); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + core::intrinsics::copy_nonoverlapping(&value, &mut dst, 1); + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + std::intrinsics::write_bytes(&mut dst, value, 1) + //~^ ERROR use of deprecated import through accidentally stabilized module `intrinsics` + } +} diff --git a/tests/ui/stability-attribute/accidentally-stable-intrinsics.stderr b/tests/ui/stability-attribute/accidentally-stable-intrinsics.stderr new file mode 100644 index 0000000000000..645437a306f74 --- /dev/null +++ b/tests/ui/stability-attribute/accidentally-stable-intrinsics.stderr @@ -0,0 +1,139 @@ +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:8:5 + | +LL | use std::intrinsics::transmute as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/accidentally-stable-intrinsics.rs:4:9 + | +LL | #![deny(deprecated)] + | ^^^^^^^^^^ +help: import this function via the `mem` module instead + | +LL - use std::intrinsics::transmute as _; +LL + use std::mem::transmute as _; + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:10:5 + | +LL | use core::intrinsics::copy as _; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use core::intrinsics::copy as _; +LL + use core::ptr::copy as _; + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:12:5 + | +LL | use std::intrinsics::copy_nonoverlapping as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use std::intrinsics::copy_nonoverlapping as _; +LL + use std::ptr::copy_nonoverlapping as _; + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:14:5 + | +LL | use core::intrinsics::write_bytes as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use core::intrinsics::write_bytes as _; +LL + use core::ptr::write_bytes as _; + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:18:5 + | +LL | copy as _, + | ^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use core::intrinsics::{ +LL + use core::ptr::{ + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:20:5 + | +LL | copy_nonoverlapping as _, + | ^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use core::intrinsics::{ +LL + use core::ptr::{ + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:22:5 + | +LL | write_bytes as _, + | ^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - use core::intrinsics::{ +LL + use core::ptr::{ + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:30:17 + | +LL | let _ = std::intrinsics::transmute::(value); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `mem` module instead + | +LL - let _ = std::intrinsics::transmute::(value); +LL + let _ = std::mem::transmute::(value); + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:32:9 + | +LL | core::intrinsics::copy(&value, &mut dst, 1); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - core::intrinsics::copy(&value, &mut dst, 1); +LL + core::ptr::copy(&value, &mut dst, 1); + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:34:9 + | +LL | core::intrinsics::copy_nonoverlapping(&value, &mut dst, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - core::intrinsics::copy_nonoverlapping(&value, &mut dst, 1); +LL + core::ptr::copy_nonoverlapping(&value, &mut dst, 1); + | + +error: use of deprecated import through accidentally stabilized module `intrinsics` + --> $DIR/accidentally-stable-intrinsics.rs:36:9 + | +LL | std::intrinsics::write_bytes(&mut dst, value, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: import this function via the `ptr` module instead + | +LL - std::intrinsics::write_bytes(&mut dst, value, 1) +LL + std::ptr::write_bytes(&mut dst, value, 1) + | + +error: aborting due to 11 previous errors + diff --git a/tests/ui/stability-attribute/allowed-through-unstable.rs b/tests/ui/stability-attribute/allowed-through-unstable.rs index 5baa0fda94037..eaa3ad9b830b4 100644 --- a/tests/ui/stability-attribute/allowed-through-unstable.rs +++ b/tests/ui/stability-attribute/allowed-through-unstable.rs @@ -1,9 +1,9 @@ -// Test for new `#[rustc_allowed_through_unstable_modules]` attribute +// Test for `#[rustc_allowed_through_unstable_modules]` attribute // //@ aux-build:allowed-through-unstable-core.rs #![crate_type = "lib"] extern crate allowed_through_unstable_core; -use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; //~WARN use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead +use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; //~WARN use of deprecated import through accidentally stabilized module `unstable_module` use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature `unstable_test_feature` diff --git a/tests/ui/stability-attribute/allowed-through-unstable.stderr b/tests/ui/stability-attribute/allowed-through-unstable.stderr index 3098f1c961f95..160dd4d4babff 100644 --- a/tests/ui/stability-attribute/allowed-through-unstable.stderr +++ b/tests/ui/stability-attribute/allowed-through-unstable.stderr @@ -1,10 +1,15 @@ -warning: use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead - --> $DIR/allowed-through-unstable.rs:8:53 +warning: use of deprecated import through accidentally stabilized module `unstable_module` + --> $DIR/allowed-through-unstable.rs:8:5 | LL | use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(deprecated)]` on by default +help: use the new path instead + | +LL - use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; +LL + use allowed_through_unstable_core::stable::OldStableTraitAllowedThoughUnstable; + | error[E0658]: use of unstable library feature `unstable_test_feature` --> $DIR/allowed-through-unstable.rs:9:36 diff --git a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs index 23c722d6e8eba..5f7e344aece60 100644 --- a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs +++ b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs @@ -6,7 +6,10 @@ #[unstable(feature = "unstable_test_feature", issue = "1")] pub mod unstable_module { #[stable(feature = "stable_test_feature", since = "1.2.0")] - #[rustc_allowed_through_unstable_modules = "use the new path instead"] + #[rustc_allowed_through_unstable_modules( + message= "use the new path instead", + module = "stable", + )] pub trait OldStableTraitAllowedThoughUnstable {} #[stable(feature = "stable_test_feature", since = "1.2.0")] From 66d9e739ff9e884fd41a5aa7fe6dfad7751b5303 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Aug 2026 15:59:27 -0700 Subject: [PATCH 20/40] Promote `wasm32-wasip3` to a tier 2 target This commit updates documentation, configuration, etc, within the compiler to promote the `wasm32-wasip3` target to tier 2. This means that precompiled binaries will be made available in `rustup` for usage. This target MCP for this change is [rust-lang/compiler-team/100][mcp]. This target requires LLVM 23 which rustc recently has updated to, and then additionally requires wasi-sdk-34 which additionally uses LLVM 23 which was also updated recently. With these ingredients in place the ABI for `wasm32-wasip3` is all lined up and ready to go. These changes were all necessary to bring cooperative threading to the target in the future, but that's not quite ready in the ecosystem yet. I've locally been testing this target and it's done well so far, but I suspect this'll need subsequent bug fixes here and there as other new issues crop up. I don't expect anything major will be necessary, however. [mcp]: https://github.com/rust-lang/compiler-team/issues/1001 --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- .../src/spec/targets/wasm32_wasip3.rs | 38 +++-- src/bootstrap/src/core/build_steps/compile.rs | 12 +- .../host-x86_64/dist-various-2/Dockerfile | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../wasm32-unknown-emscripten.md | 17 ++- .../wasm32-unknown-unknown.md | 5 +- .../src/platform-support/wasm32-wasip3.md | 143 +++++++++++++++--- 8 files changed, 158 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 25003e071beb7..8c6998407e89e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -4129,7 +4129,7 @@ fn add_lld_args( // `lld` as the linker. // // Note that wasm targets skip this step since the only option there anyway - // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around + // is to use LLD but component-producing targets rely on a wrapper around // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { cmd.cc_arg("-fuse-ld=lld"); diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs index 9e981cd73f5a7..dea9a130e6e56 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs @@ -2,38 +2,44 @@ //! `wasm32-wasip2`, then WASIp3. The main feature of WASIp3 is native async //! support in the component model itself. //! -//! Like `wasm32-wasip2` this target produces a component by default. Support -//! for `wasm32-wasip3` is very early as of the time of this writing so -//! components produced will still import WASIp2 APIs, but that's ok since it's -//! all component-model-level imports anyway. Over time the imports of the -//! standard library will change to WASIp3. +//! Like `wasm32-wasip2` this target produces a component by default. use crate::spec::{Cc, Env, LinkerFlavor, Target, add_link_args}; pub(crate) fn target() -> Target { - // As of now WASIp3 is a lightly edited wasip2 target, so start with that - // and this may grow over time as more features are supported. + // For now wasip3 is a lightly-edited wasip2 target. let mut target = super::wasm32_wasip2::target(); target.llvm_target = "wasm32-wasip3".into(); target.metadata = crate::spec::TargetMetadata { description: Some("WebAssembly".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(true), }; target.options.env = Env::P3; - // The `--cooperative-threading` flag to the linker dictates the ABI that's - // being used on this target which is to store the stack pointer in a - // component model intrinsic location, for example, rather than a wasm - // global. - // - // Note that this is only specified for `Cc::No`, because when `clang` is - // being used as a linker it'll already pass this. add_link_args( &mut target.pre_link_args, LinkerFlavor::WasmLld(Cc::No), - &["--cooperative-threading"], + &[ + // The `--cooperative-threading` flag to the linker dictates the ABI + // that's being used on this target which is to store the stack + // pointer in a component model intrinsic location, for example, + // rather than a wasm global. + // + // Note that this is only specified for `Cc::No`, because when + // `clang` is being used as a linker it'll already pass this. + "--cooperative-threading", + // This is used as the wasi-libc-defined symbol here is required for + // this target to function. The Rust compiler's symbol exports + // otherwise don't know about this symbol so it's manually exported + // here. + // + // Note that this additionally is only specified for `Cc::No` + // because when `clang` is used the symbol exports happen naturally + // and this isn't needed. + "--export-if-defined=__wasm_task_hook", + ], ); target diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index fb83e4ae5754c..b1157ef381013 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -439,15 +439,6 @@ fn copy_self_contained_objects( ) }); - // wasm32-wasip3 doesn't exist in wasi-libc yet, so instead use libs - // from the wasm32-wasip2 target. Once wasi-libc supports wasip3 this - // should be deleted and the native objects should be used. - let srcdir = if target == "wasm32-wasip3" { - assert!(!srcdir.exists(), "wasip3 support is in wasi-libc, this should be updated now"); - builder.wasi_libdir(TargetSelection::from_user("wasm32-wasip2")).unwrap() - } else { - srcdir - }; for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] { copy_and_stamp( builder, @@ -2529,7 +2520,8 @@ impl CommandLineStep for Assemble { } // In addition to `rust-lld` also install `wasm-component-ld` when - // is enabled. This is used by the `wasm32-wasip2` target of Rust. + // is enabled. This is used by targets that produce WebAssembly + // components in Rust such as `wasm32-wasip{2,3}`. if builder.tool_enabled("wasm-component-ld") { let wasm_component = builder.ensure( crate::core::build_steps::tool::WasmComponentLd::for_use_by_compiler( diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index efdbcbae63467..d753d16aff66c 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -104,6 +104,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,wasm32-wasip1 ENV TARGETS=$TARGETS,wasm32-wasip1-threads ENV TARGETS=$TARGETS,wasm32-wasip2 +ENV TARGETS=$TARGETS,wasm32-wasip3 ENV TARGETS=$TARGETS,wasm32v1-none ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7518ee9fabbbc..25cecb9be3c2c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -218,6 +218,7 @@ target | std | notes [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASIp1 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | WebAssembly with WASIp2 +[`wasm32-wasip3`](platform-support/wasm32-wasip3.md) | ✓ | WebAssembly with WASIp3 [`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64 @@ -445,7 +446,6 @@ target | std | host | notes [`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv8M Mainline with NuttX, hardfloat [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly [`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI) -[`wasm32-wasip3`](platform-support/wasm32-wasip3.md) | ✓ | | WebAssembly with WASIp3 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178 diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md index 0d15097468b17..fcf6e42be224b 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md @@ -25,14 +25,15 @@ does not (easily) support interop with C/C++ code. Please refer to the [wasm-bindgen](https://crates.io/crates/wasm-bindgen) crate in case you want to interoperate with JavaScript with this target. -Like Emscripten, the WASI targets [`wasm32-wasip1`](./wasm32-wasip1.md) and -[`wasm32-wasip2`](./wasm32-wasip2.md) also provide access to the host environment, -support interop with C/C++ (and other languages), and support most of the Rust -standard library. While the WASI targets are portable across different hosts -(web and non-web), WASI has no standard way of accessing web APIs, whereas -Emscripten has the ability to run arbitrary JS from WASM and access many web APIs. -If you are only targeting the web and need to access web APIs, the -`wasm32-unknown-emscripten` target may be preferable. +Like Emscripten, the WASI targets [`wasm32-wasip1`](./wasm32-wasip1.md), +[`wasm32-wasip2`](./wasm32-wasip2.md), and +[`wasm32-wasip3`](./wasm32-wasip3.md), also provide access to the host +environment, support interop with C/C++ (and other languages), and support most +of the Rust standard library. While the WASI targets are portable across +different hosts (web and non-web), WASI has no standard way of accessing web +APIs, whereas Emscripten has the ability to run arbitrary JS from WASM and +access many web APIs. If you are only targeting the web and need to access web +APIs, the `wasm32-unknown-emscripten` target may be preferable. ## Target maintainers diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index 3dc608e704308..362bf6f255d9d 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -15,8 +15,9 @@ but many parts of the standard library do not work and return errors. For example `println!` does nothing, `std::fs` always return errors, and `std::thread::spawn` will panic. There is no means by which this can be overridden. For a WebAssembly target that more fully supports the standard -library see the [`wasm32-wasip1`](./wasm32-wasip1.md) or -[`wasm32-wasip2`](./wasm32-wasip2.md) targets. +library see the [`wasm32-wasip1`](./wasm32-wasip1.md), +[`wasm32-wasip2`](./wasm32-wasip2.md), or +[`wasm32-wasip3`](./wasm32-wasip3.md), targets. The `wasm32-unknown-unknown` target has full support for the `core` and `alloc` crates. It additionally supports the `HashMap` type in the `std` crate, although diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip3.md b/src/doc/rustc/src/platform-support/wasm32-wasip3.md index e8063a1bdcfed..4807adc0c2982 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip3.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip3.md @@ -1,42 +1,49 @@ # `wasm32-wasip3` -**Tier: 3** +**Tier: 2** The `wasm32-wasip3` target is the next stage of evolution of the [`wasm32-wasip2`](./wasm32-wasip2.md) target. The `wasm32-wasip3` target enables the Rust standard library to use WASIp3 APIs to implement various pieces of functionality. WASIp3 brings native async support over WASIp2, which integrates -well with Rust's `async` ecosystem. - -> **Note**: As of 2025-10-01 WASIp3 has not yet been approved by the WASI -> subgroup of the WebAssembly Community Group. Development is expected to -> conclude in late 2025 or early 2026. Until then the Rust standard library -> won't actually use WASIp3 APIs on the `wasm32-wasip3` target as they are not -> yet stable and would reduce the stability of this target. Once WASIp3 is -> approved, however, the standard library will update to use WASIp3 natively. - -> **Note**: This target does not yet build as of 2025-10-01 due to and update -> needed in the `libc` crate. Using it will require a `[patch]` for now. - -> **Note**: Until the standard library is fully migrated to use the `wasip3` -> crate then components produced for `wasm32-wasip3` may import WASIp2 APIs. -> This is considered a transitionary phase until fully support of libstd is -> implemented. +well with Rust's `async` ecosystem. Additionally a future release of Rust's +`wasm32-wasip3` target will support cooperative threading and `std::thread` +APIs. + +The original proposal for adding this target can be found in +[rust-lang/compiler-team#1001] and this target is first available on stable in +Rust 1.100.0. A notable major change from historical WebAssembly targets is that +the ABI of this target is slightly different. The linear memory shadow stack +pointer is stored in a component model task context slot instead of a +WebAssembly` global`. Additionally the base pointer of TLS is managed +differently than other targets. These changes are made to enable cooperative +multithreading on this target. + +> **Note**: As of 2026-09-03 cooperative multithreading is not yet supported on +> this target in Rust. The component model specification and library support +> work for this is in-development and not yet complete, but it's expected to be +> complete before the end of the year. Before that time spawning a thread via +> `std::thread` will return an error. Note though that this support can be +> tested through the [instructions below](#testing-cooperative-multithreading). + +[rust-lang/compiler-team#1001]: https://github.com/rust-lang/compiler-team/issues/1001 ## Target maintainers [@alexcrichton](https://github.com/alexcrichton) +[@yoshuawuyts](https://github.com/yoshuawuyts) ## Requirements -This target is cross-compiled. The target supports `std` fully. +This target is cross-compiled. The target supports `std` fully. This target +requires LLVM 23 to be used and additionally requires `wasi-sdk-34`-or-later if +you're building it locally or linking with this externally. ## Platform requirements -The WebAssembly runtime should support both WASIp2 and WASIp3. Runtimes also -are required to support components since this target outputs a component as -opposed to a core wasm module. Two example runtimes for WASIp3 are [Wasmtime] -and [Jco]. +WebAssembly runtimes that want to execute components compiled for this target +must support WASI 0.3.0 and the requisite required component model features +(notably async). Two example runtimes for WASIp3 are [Wasmtime] and [Jco]. [Wasmtime]: https://wasmtime.dev/ [Jco]: https://github.com/bytecodealliance/jco @@ -44,14 +51,14 @@ and [Jco]. ## Building the target To build this target first acquire a copy of -[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 22 +[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 34 is the minimum needed. Next configure the `WASI_SDK_PATH` environment variable to point to where this is installed. For example: ```text -export WASI_SDK_PATH=/path/to/wasi-sdk-22.0 +export WASI_SDK_PATH=/path/to/wasi-sdk-34.0 ``` Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld` @@ -81,3 +88,91 @@ It's recommended to conditionally compile code for this target with: The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. + +## Testing Cooperative Multithreading + +The [component model specification][spec] is in the process of adding intrinsics +to support cooperative multithreading in a component guest. These intrinsics can +be found in the [explainer] and are all gated by the 🧵 emoji. Support for +cooperative multithreading is a work-in-progress and not yet complete, but the +adventurous can configure this target to go ahead and test things out. + +The majority of changes necessary to get cooperative multithreading lie within +Rust's [wasi-libc dependency][wasi-libc]. This means that to test cooperative +multithreading a different build than the default wasi-libc needs to be used. +Starting with [wasi-sdk-34] there is a temporary sysroot which contains support +for a wasip3 target that has multithreading enabled in wasi-libc. To test out +the `wasm32-wasip3` Rust target with threads your compilation needs to be +configured to use this sysroot. + +An example of doing this is this program: + +```rust +fn main() { + std::thread::spawn(|| { + println!("hi"); + }) + .join() + .unwrap(); +} +``` + +is compiled and run by default as: + +```console +$ rustc foo.rs --target wasm32-wasip3 +$ wasmtime foo.wasm + +thread 'main' (1) panicked at library/std/src/thread/functions.rs:131:29: +failed to spawn thread: Os { code: 58, kind: Unsupported, message: "Not supported" } +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +Error: failed to run main module `foo.wasm` + +... +``` + +which shows that by default threads cannot be spawned. By configuring a custom +sysroot to be used, however: + +```console +$ rustc foo.rs --target wasm32-wasip3 \ + -Clink-self-contained=n \ + -Clinker=$WASI_SDK_PATH/bin/wasm32-wasip3-clang \ + -Clink-arg=--sysroot=$WASI_SDK_PATH/share/wasi-sysroot/experimental-coop-threads \ + -Clink-arg=-Wl,--export=cabi_realloc +$ wasmtime -W component-model-threading foo.wasm +hi +``` + +Here `-Clink-self-contained=n` avoids the vendored files in the standard library +which come from a build of wasi-libc incompatible with cooperative +multithreading. The `-Clinker` flag changes to use `clang` to be able to pass a +custom `--sysroot` argument and follow its logic for startup objects. The +`--sysroot` flag then points to the experimental sysroot for coop threads and +`--export` is required right now as a minor workaround. + +When compiling with Cargo you can use these environment variables: + +```console +$ export CARGO_TARGET_WASM32_WASIP3_LINKER=$WASI_SDK_PATH/bin/wasm32-wasip3-clang +$ export CARGO_TARGET_WASM32_WASIP3_RUNNER='wasmtime -W component-model-threading' +$ export CARGO_TARGET_WASM32_WASIP3_RUSTFLAGS="\ + -Clink-self-contained=n \ + -Clink-arg=--sysroot=$WASI_SDK_PATH/share/wasi-sysroot/experimental-coop-threads \ + -Clink-arg=-Wl,--export=cabi_realloc" +$ cargo run --target wasm32-wasip3 +hi +``` + +Standard synchronization primitives in `std::thread` and `std::sync` should all +work on this target with cooperative multithreading. Should you run into any +issues please don't hesitate to file an issue and cc the target maintainers. + +Note that it is currently intended that by the end of 2026 this support will all +be enabled by default and this section of the documentation will be deleted +since working with threads should "just work". + +[spec]: https://github.com/webassembly/component-model +[explainer]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md +[wasi-libc]: https://github.com/webassembly/wasi-libc +[wasi-sdk-34]: https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-34 From be0994f8f83d85f7cb7060b5b3db2f19daa2ba29 Mon Sep 17 00:00:00 2001 From: b1yd <2156864690@qq.com> Date: Thu, 3 Sep 2026 22:15:49 +0800 Subject: [PATCH 21/40] fix-incorrect-meta-span --- compiler/rustc_parse/src/parser/attr.rs | 2 +- tests/ui/macros/correct-meta-item-span.rs | 8 +++++++ tests/ui/macros/correct-meta-item-span.stderr | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/ui/macros/correct-meta-item-span.rs create mode 100644 tests/ui/macros/correct-meta-item-span.stderr diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 0f49e3c02873d..b2ad898311cc3 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -442,7 +442,7 @@ impl<'a> Parser<'a> { }) .unwrap() .node; - Ok(attr_item.meta(attr_item.path.span).unwrap()) + Ok(attr_item.meta(attr_item.span).unwrap()) } else { self.unexpected_any() }; diff --git a/tests/ui/macros/correct-meta-item-span.rs b/tests/ui/macros/correct-meta-item-span.rs new file mode 100644 index 0000000000000..9c3e464024ded --- /dev/null +++ b/tests/ui/macros/correct-meta-item-span.rs @@ -0,0 +1,8 @@ +// The span of the suggestion should be correct and not ICE on this code (#161472) +macro_rules! m { ($m:meta) => { #[derive($m)] pub struct S; }; } + +m!(a(::b::c)); +//~^ ERROR traits in `#[derive(...)]` don't accept arguments +//~| ERROR cannot find derive macro `a` in this scope +//~| ERROR cannot find derive macro `a` in this scope +fn main(){} diff --git a/tests/ui/macros/correct-meta-item-span.stderr b/tests/ui/macros/correct-meta-item-span.stderr new file mode 100644 index 0000000000000..8091f3adf70eb --- /dev/null +++ b/tests/ui/macros/correct-meta-item-span.stderr @@ -0,0 +1,22 @@ +error: traits in `#[derive(...)]` don't accept arguments + --> $DIR/correct-meta-item-span.rs:4:5 + | +LL | m!(a(::b::c)); + | ^^^^^^^^ help: remove the arguments + +error: cannot find derive macro `a` in this scope + --> $DIR/correct-meta-item-span.rs:4:4 + | +LL | m!(a(::b::c)); + | ^ + +error: cannot find derive macro `a` in this scope + --> $DIR/correct-meta-item-span.rs:4:4 + | +LL | m!(a(::b::c)); + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors + From aea90f17e144e732c9bedf52a37844b3d6c3449c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 2 Sep 2026 22:19:51 +0200 Subject: [PATCH 22/40] Implement `Rng` for `Box` --- library/alloc/src/boxed.rs | 8 ++++++++ library/alloc/src/lib.rs | 1 + 2 files changed, 9 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 473f01660bdb4..0147c719c32b2 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2568,3 +2568,11 @@ unsafe impl Allocator for Box { unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } + +#[unstable(feature = "random", issue = "130703")] +impl core::random::Rng for Box { + #[inline] + fn fill_bytes(&mut self, bytes: &mut [u8]) { + (**self).fill_bytes(bytes) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 89b15a169dce0..539bf5c532552 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -160,6 +160,7 @@ #![feature(ptr_cast_slice)] #![feature(ptr_internals)] #![feature(ptr_metadata)] +#![feature(random)] #![feature(raw_os_error_ty)] #![feature(rev_into_inner)] #![feature(seek_stream_len)] From dc3b394f8a18a517edad5069b7588ebe2ea0476a Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:09:54 +0100 Subject: [PATCH 23/40] std: fix typo --- library/std/src/sys/fs/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 74b4322d027c5..58262d7557fce 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -953,7 +953,7 @@ impl Iterator for ReadDir { } } -/// Aborts the process if a file desceriptor is not open, if debug asserts are enabled +/// Aborts the process if a file descriptor is not open, if debug asserts are enabled /// /// Many IO syscalls can't be fully trusted about EBADF error codes because those /// might get bubbled up from a remote FUSE server rather than the file descriptor From 1545557cd24e8ba16692756654334e51c3a42037 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Sep 2026 09:29:07 +1000 Subject: [PATCH 24/40] Introduce `rustc_middle::middel::resolve` There are various types used to carry name resolution results across crate boundaries. They are scattered across places like `rustc_middle::ty`, `rustc_middle::metadata`, and `rustc_hir::def`. This commit moves them into the new module, a more logical place for them to live. As part of this it eliminates the small `rustc_middle::metadata` module. One nice consequence of this change: it removes the single use of a `LocalDefId` in `rustc_ast`. (This is what got my attention in the first place.) --- compiler/rustc_ast/src/ast.rs | 19 -- compiler/rustc_ast_lowering/src/item.rs | 3 +- compiler/rustc_ast_lowering/src/lib.rs | 7 +- compiler/rustc_ast_lowering/src/path.rs | 3 +- compiler/rustc_hir/src/def.rs | 100 +----- compiler/rustc_interface/src/passes.rs | 7 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- .../rustc_metadata/src/rmeta/parameterized.rs | 6 +- compiler/rustc_middle/src/arena.rs | 15 +- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_middle/src/metadata.rs | 53 --- compiler/rustc_middle/src/middle/mod.rs | 1 + compiler/rustc_middle/src/middle/resolve.rs | 309 ++++++++++++++++++ .../src/middle/resolve_bound_vars.rs | 3 +- compiler/rustc_middle/src/queries.rs | 16 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 149 +-------- compiler/rustc_passes/src/diagnostics.rs | 3 +- compiler/rustc_passes/src/lang_items.rs | 3 +- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 3 +- compiler/rustc_resolve/src/ident.rs | 3 +- compiler/rustc_resolve/src/imports.rs | 4 +- compiler/rustc_resolve/src/late.rs | 5 +- compiler/rustc_resolve/src/lib.rs | 16 +- src/librustdoc/clean/mod.rs | 2 +- .../passes/lint/redundant_explicit_links.rs | 3 +- 28 files changed, 381 insertions(+), 365 deletions(-) delete mode 100644 compiler/rustc_middle/src/metadata.rs create mode 100644 compiler/rustc_middle/src/middle/resolve.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 426fc4e7be228..b4a1e41c95bf0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -29,7 +29,6 @@ use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHashe use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, StableHash, Walkable}; pub use rustc_span::AttrId; -use rustc_span::def_id::LocalDefId; use rustc_span::{ ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, LocalExpnId, Span, Spanned, Symbol, kw, respan, sym, @@ -4445,24 +4444,6 @@ impl TryFrom for ForeignItemKind { } pub type ForeignItem = Item; - -/// Fragment of the AST according to "HIR owner" semantics. -/// -/// This is used to map each `LocalDefId` to its content's AST. -#[derive(Debug)] -pub enum AstOwner { - /// This definition does not correspond to a HIR owner. - NonOwner, - /// This definition corresponds to a nested `use` tree. - /// The `LocalDefId` points to its HIR owner. - NestedUseTree(LocalDefId), - Crate(Box), - Item(Box), - TraitItem(Box), - ImplItem(Box), - ForeignItem(Box), -} - // Some nodes are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fc3fa99fa0644..e97c5c52b8823 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -8,9 +8,10 @@ use rustc_hir::{ self as hir, CRATE_OWNER_ID, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr, }; +use rustc_middle::middle::resolve::ResolverAstLowering; use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::data_structures::IndexMap; -use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5b76606d101bc..87d118e245001 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,7 +55,7 @@ use rustc_data_structures::unord::ExtendUnord; use rustc_errors::codes::*; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, ErrorGuaranteed}; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; +use rustc_hir::def::{DefKind, Namespace, PerNS, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::PerParentDisambiguatorState; use rustc_hir::lints::DelayedLint; @@ -65,9 +65,12 @@ use rustc_hir::{ }; use rustc_index::{Idx, IndexVec}; use rustc_macros::extension; +use rustc_middle::middle::resolve::{ + AstOwner, LifetimeRes, PartialRes, PerOwnerResolverData, ResolverAstLowering, +}; use rustc_middle::queries::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{PerOwnerResolverData, ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_session::diagnostics::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 261fcd18d96ba..387aa7566b42a 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -2,9 +2,10 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; use rustc_errors::StashKey; -use rustc_hir::def::{DefKind, PartialRes, PerNS, Res}; +use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; +use rustc_middle::middle::resolve::PartialRes; use rustc_middle::{span_bug, ty}; use rustc_session::diagnostics::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 010ecb1cd3d98..f1047e6c0bab4 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -4,12 +4,11 @@ use std::fmt::Debug; use rustc_ast as ast; use rustc_ast::NodeId; -use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_hir_id::HirId; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::Symbol; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::DefId; use rustc_span::hygiene::MacroKind; use crate as hir; @@ -587,63 +586,6 @@ impl IntoDiagArg for Res { } } -/// The result of resolving a path before lowering to HIR, -/// with "module" segments resolved and associated item -/// segments deferred to type checking. -/// `base_res` is the resolution of the resolved part of the -/// path, `unresolved_segments` is the number of unresolved -/// segments. -/// -/// ```text -/// module::Type::AssocX::AssocY::MethodOrAssocType -/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// base_res unresolved_segments = 3 -/// -/// ::AssocX::AssocY::MethodOrAssocType -/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ -/// base_res unresolved_segments = 2 -/// ``` -#[derive(Copy, Clone, Debug)] -pub struct PartialRes { - base_res: Res, - unresolved_segments: usize, -} - -impl PartialRes { - #[inline] - pub fn new(base_res: Res) -> Self { - PartialRes { base_res, unresolved_segments: 0 } - } - - #[inline] - pub fn with_unresolved_segments(base_res: Res, mut unresolved_segments: usize) -> Self { - if base_res == Res::Err { - unresolved_segments = 0 - } - PartialRes { base_res, unresolved_segments } - } - - #[inline] - pub fn base_res(&self) -> Res { - self.base_res - } - - #[inline] - pub fn unresolved_segments(&self) -> usize { - self.unresolved_segments - } - - #[inline] - pub fn full_res(&self) -> Option> { - (self.unresolved_segments == 0).then_some(self.base_res) - } - - #[inline] - pub fn expect_full_res(&self) -> Res { - self.full_res().expect("unexpected unresolved segments") - } -} - /// Different kinds of symbols can coexist even if they share the same textual name. /// Therefore, they each have a separate universe (known as a "namespace"). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)] @@ -933,43 +875,3 @@ impl Res { matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..)) } } - -/// Resolution for a lifetime appearing in a type. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum LifetimeRes { - /// Successfully linked the lifetime to a generic parameter. - Param { - /// Id of the generic parameter that introduced it. - param: LocalDefId, - /// Id of the introducing place. That can be: - /// - an item's id, for the item's generic parameters; - /// - a TraitRef's ref_id, identifying the `for<...>` binder; - /// - a FnPtr type's id. - /// - /// This information is used for impl-trait lifetime captures, to know when to or not to - /// capture any given lifetime. - binder: NodeId, - }, - /// Created a generic parameter for an anonymous lifetime. - Fresh { - /// Id of the generic parameter that introduced it. - /// - /// Creating the associated `LocalDefId` is the responsibility of lowering. - param: NodeId, - /// Kind of elided lifetime - kind: hir::MissingLifetimeKind, - }, - /// This variant is used for anonymous lifetimes that we did not resolve during - /// late resolution. Those lifetimes will be inferred by typechecking. - Infer, - /// `'static` lifetime. - Static, - /// Resolution failure. - Error(rustc_span::ErrorGuaranteed), - /// HACK: This is used to recover the NodeId of an elided lifetime. - ElidedAnchor { start: NodeId, end: NodeId }, -} - -// FxIndexMap is necessary because its data ends up in .rmeta files, -// so its iteration order must be consistent. See #159677 for context. -pub type DocLinkResMap = FxIndexMap<(Symbol, Namespace), Option>>; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c829864b02288..ebdb82e2b4fe6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -30,6 +30,7 @@ use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_sto use rustc_metadata::EncodedMetadata; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; +use rustc_middle::middle::resolve::{ResolverAstLowering, ResolverGlobalCtxt}; use rustc_middle::ty::{self, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; use rustc_parse::lexer::StripTokens; @@ -792,11 +793,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P fn resolver_for_lowering_raw<'tcx>( tcx: TyCtxt<'tcx>, (): (), -) -> ( - &'tcx Steal>, - &'tcx Steal, - &'tcx ty::ResolverGlobalCtxt, -) { +) -> (&'tcx Steal>, &'tcx Steal, &'tcx ResolverGlobalCtxt) { let arenas = WorkerLocal::new(|_| Resolver::arenas()); let _ = tcx.registered_attr_tools(()); // Uses `crate_for_resolver`. let _ = tcx.registered_lint_tools(()); // Uses `crate_for_resolver`. diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 8fe1d6561d135..08053bb2c6a60 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -10,8 +10,8 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; -use rustc_middle::metadata::{AmbigModChild, ModChild}; use rustc_middle::middle::exported_symbols::ExportedSymbol; +use rustc_middle::middle::resolve::{AmbigModChild, ModChild}; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::queries::ExternProviders; use rustc_middle::query::LocalCrate; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 064d906293ae8..0d6122d6748cb 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -15,7 +15,7 @@ use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, MacroKinds}; +use rustc_hir::def::{CtorKind, DefKind, MacroKinds}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::{PreciseCapturingArgKind, attrs}; @@ -24,12 +24,12 @@ use rustc_index::bit_set::DenseBitSet; use rustc_macros::{ BlobDecodable, Decodable, Encodable, LazyDecodable, MetadataEncodable, TyDecodable, TyEncodable, }; -use rustc_middle::metadata::{AmbigModChild, ModChild}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::lib_features::FeatureStability; +use rustc_middle::middle::resolve::{AmbigModChild, DocLinkResMap, ModChild}; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::mir::ConstValue; diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index f19737bb936be..4eb922446b71b 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -104,18 +104,18 @@ trivially_parameterized_over_tcx! { rustc_hir::attrs::StrippedCfgItem, rustc_hir::attrs::lang_items::LangItem, rustc_hir::def::DefKind, - rustc_hir::def::DocLinkResMap, rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_index::bit_set::DenseBitSet, - rustc_middle::metadata::AmbigModChild, - rustc_middle::metadata::ModChild, rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile, rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs, rustc_middle::middle::exported_symbols::SymbolExportInfo, rustc_middle::middle::lib_features::FeatureStability, + rustc_middle::middle::resolve::AmbigModChild, + rustc_middle::middle::resolve::DocLinkResMap, + rustc_middle::middle::resolve::ModChild, rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, rustc_middle::mir::ConstQualifs, rustc_middle::mir::ConstValue, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 5995c048d8b92..3c973d7d3a5a2 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,18 +36,21 @@ rustc_arena::declare_arena! { rustc_hir::def_id::LocalDefId, rustc_middle::ty::DefinitionSiteHiddenType<'tcx>, >, - resolver: rustc_data_structures::steal::Steal>, + resolver: + rustc_data_structures::steal::Steal< + rustc_middle::middle::resolve::ResolverAstLowering<'tcx> + >, index_ast: rustc_index::IndexVec< rustc_span::def_id::LocalDefId, rustc_data_structures::steal::Steal<( - std::sync::Arc>, - rustc_ast::AstOwner + std::sync::Arc>, + rustc_middle::middle::resolve::AstOwner )> >, crate_alone: rustc_data_structures::steal::Steal, crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, - resolutions: rustc_middle::ty::ResolverGlobalCtxt, + resolutions: rustc_middle::middle::resolve::ResolverGlobalCtxt, const_allocs: rustc_middle::mir::interpret::Allocation, region_scope_tree: rustc_middle::middle::region::ScopeTree, // Required for the incremental on-disk cache @@ -128,9 +131,9 @@ rustc_arena::declare_arena! { rustc_middle::ty::EarlyBinder<'tcx, Ty<'tcx>> >, external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, - doc_link_resolutions: rustc_hir::def::DocLinkResMap, + doc_link_resolutions: rustc_middle::middle::resolve::DocLinkResMap, stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem, - mod_child: rustc_middle::metadata::ModChild, + mod_child: rustc_middle::middle::resolve::ModChild, features: rustc_feature::Features, specialization_graph: rustc_middle::traits::specialization_graph::Graph, crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 993cb6e7769dd..48d90f9c704fc 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -77,7 +77,6 @@ pub mod hooks; pub mod ich; pub mod infer; pub mod lint; -pub mod metadata; pub mod middle; pub mod mir; pub mod mono; diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs deleted file mode 100644 index 0c9b44a93a20e..0000000000000 --- a/compiler/rustc_middle/src/metadata.rs +++ /dev/null @@ -1,53 +0,0 @@ -use rustc_hir::def::Res; -use rustc_macros::{StableHash, TyDecodable, TyEncodable}; -use rustc_span::Ident; -use rustc_span::def_id::{DefId, ModId}; -use smallvec::SmallVec; - -use crate::ty; - -/// A simplified version of `ImportKind` from resolve. -/// `DefId`s here correspond to `use` and `extern crate` items themselves, not their targets. -#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, StableHash)] -pub enum Reexport { - Single(DefId), - Glob(DefId), - ExternCrate(DefId), - MacroUse, - MacroExport, -} - -impl Reexport { - pub fn id(self) -> Option { - match self { - Reexport::Single(id) | Reexport::Glob(id) | Reexport::ExternCrate(id) => Some(id), - Reexport::MacroUse | Reexport::MacroExport => None, - } - } -} - -/// This structure is supposed to keep enough data to re-create `Decl`s for other crates -/// during name resolution. Right now the bindings are not recreated entirely precisely so we may -/// need to add more data in the future to correctly support macros 2.0, for example. -/// Module child can be either a proper item or a reexport (including private imports). -/// In case of reexport all the fields describe the reexport item itself, not what it refers to. -#[derive(Debug, TyEncodable, TyDecodable, StableHash)] -pub struct ModChild { - /// Name of the item. - pub ident: Ident, - /// Resolution result corresponding to the item. - /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. - pub res: Res, - /// Visibility of the item. - pub vis: ty::Visibility, - /// Reexport chain linking this module child to its original reexported item. - /// Empty if the module child is a proper item. - pub reexport_chain: SmallVec<[Reexport; 2]>, -} - -/// Same as `ModChild`, however, it includes ambiguity error. -#[derive(Debug, TyEncodable, TyDecodable, StableHash)] -pub struct AmbigModChild { - pub main: ModChild, - pub second: ModChild, -} diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 7967a6222c3be..924dcceb9cef8 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -34,5 +34,6 @@ pub mod lib_features { } pub mod privacy; pub mod region; +pub mod resolve; pub mod resolve_bound_vars; pub mod stability; diff --git a/compiler/rustc_middle/src/middle/resolve.rs b/compiler/rustc_middle/src/middle/resolve.rs new file mode 100644 index 0000000000000..2958048103320 --- /dev/null +++ b/compiler/rustc_middle/src/middle/resolve.rs @@ -0,0 +1,309 @@ +//! This module contains types that carry name resolution results from `rustc_resolve` to a +//! consumer in another crate (e.g. AST lowering, metadata, or a query). + +use rustc_ast::node_id::NodeMap; +use rustc_ast::{self as ast, NodeId}; +use rustc_attr_ir::StrippedCfgItem; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::steal::Steal; +use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_errors::{ErrorGuaranteed, LintBuffer}; +use rustc_hir::def::{DefKind, Namespace, PerNS, Res}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalModId, ModId}; +use rustc_hir::definitions::PerParentDisambiguatorState; +use rustc_hir::{MissingLifetimeKind, TraitCandidate}; +use rustc_macros::{StableHash, TyDecodable, TyEncodable}; +use rustc_span::{ExpnId, Ident, Span, Symbol}; +use smallvec::SmallVec; + +use crate::middle::privacy::EffectiveVisibilities; +use crate::ty::Visibility; + +/// The result of resolving a path before lowering to HIR, +/// with "module" segments resolved and associated item +/// segments deferred to type checking. +/// `base_res` is the resolution of the resolved part of the +/// path, `unresolved_segments` is the number of unresolved +/// segments. +/// +/// ```text +/// module::Type::AssocX::AssocY::MethodOrAssocType +/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/// base_res unresolved_segments = 3 +/// +/// ::AssocX::AssocY::MethodOrAssocType +/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ +/// base_res unresolved_segments = 2 +/// ``` +#[derive(Copy, Clone, Debug)] +pub struct PartialRes { + base_res: Res, + unresolved_segments: usize, +} + +impl PartialRes { + #[inline] + pub fn new(base_res: Res) -> Self { + PartialRes { base_res, unresolved_segments: 0 } + } + + #[inline] + pub fn with_unresolved_segments(base_res: Res, mut unresolved_segments: usize) -> Self { + if base_res == Res::Err { + unresolved_segments = 0 + } + PartialRes { base_res, unresolved_segments } + } + + #[inline] + pub fn base_res(&self) -> Res { + self.base_res + } + + #[inline] + pub fn unresolved_segments(&self) -> usize { + self.unresolved_segments + } + + #[inline] + pub fn full_res(&self) -> Option> { + (self.unresolved_segments == 0).then_some(self.base_res) + } + + #[inline] + pub fn expect_full_res(&self) -> Res { + self.full_res().expect("unexpected unresolved segments") + } +} + +/// Resolution for a lifetime appearing in a type. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum LifetimeRes { + /// Successfully linked the lifetime to a generic parameter. + Param { + /// Id of the generic parameter that introduced it. + param: LocalDefId, + /// Id of the introducing place. That can be: + /// - an item's id, for the item's generic parameters; + /// - a TraitRef's ref_id, identifying the `for<...>` binder; + /// - a FnPtr type's id. + /// + /// This information is used for impl-trait lifetime captures, to know when to or not to + /// capture any given lifetime. + binder: NodeId, + }, + /// Created a generic parameter for an anonymous lifetime. + Fresh { + /// Id of the generic parameter that introduced it. + /// + /// Creating the associated `LocalDefId` is the responsibility of lowering. + param: NodeId, + /// Kind of elided lifetime + kind: MissingLifetimeKind, + }, + /// This variant is used for anonymous lifetimes that we did not resolve during + /// late resolution. Those lifetimes will be inferred by typechecking. + Infer, + /// `'static` lifetime. + Static, + /// Resolution failure. + Error(ErrorGuaranteed), + /// HACK: This is used to recover the NodeId of an elided lifetime. + ElidedAnchor { start: NodeId, end: NodeId }, +} + +/// A simplified version of `ImportKind` from resolve. +/// `DefId`s here correspond to `use` and `extern crate` items themselves, not their targets. +#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, StableHash)] +pub enum Reexport { + Single(DefId), + Glob(DefId), + ExternCrate(DefId), + MacroUse, + MacroExport, +} + +impl Reexport { + pub fn id(self) -> Option { + match self { + Reexport::Single(id) | Reexport::Glob(id) | Reexport::ExternCrate(id) => Some(id), + Reexport::MacroUse | Reexport::MacroExport => None, + } + } +} + +/// This structure is supposed to keep enough data to re-create `Decl`s for other crates +/// during name resolution. Right now the bindings are not recreated entirely precisely so we may +/// need to add more data in the future to correctly support macros 2.0, for example. +/// Module child can be either a proper item or a reexport (including private imports). +/// In case of reexport all the fields describe the reexport item itself, not what it refers to. +#[derive(Debug, TyEncodable, TyDecodable, StableHash)] +pub struct ModChild { + /// Name of the item. + pub ident: Ident, + /// Resolution result corresponding to the item. + /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. + pub res: Res, + /// Visibility of the item. + pub vis: Visibility, + /// Reexport chain linking this module child to its original reexported item. + /// Empty if the module child is a proper item. + pub reexport_chain: SmallVec<[Reexport; 2]>, +} + +/// Same as `ModChild`, however, it includes ambiguity error. +#[derive(Debug, TyEncodable, TyDecodable, StableHash)] +pub struct AmbigModChild { + pub main: ModChild, + pub second: ModChild, +} + +#[derive(Debug, StableHash)] +pub struct ResolverGlobalCtxt { + pub visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, + /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. + pub expn_that_defined: UnordMap, + pub effective_visibilities: EffectiveVisibilities, + // FIXME: This table contains ADTs reachable from macro 2.0. + // Currently, reachability of a definition from a macro is determined by nominal visibility + // (see `compute_effective_visibilities`). This is incorrect and leads to the necessity + // of traversing ADT fields in `rustc_privacy`. Remove this workaround once the + // correct reachability logic is implemented for macros. + pub macro_reachable_adts: FxIndexMap>, + pub extern_crate_map: UnordMap, + pub maybe_unused_trait_imports: FxIndexSet, + pub module_children: LocalDefIdMap>, + pub ambig_module_children: LocalDefIdMap>, + pub glob_map: FxIndexMap>, + pub main_def: Option, + pub trait_impls: FxIndexMap>, + /// A list of proc macro LocalDefIds, written out in the order in which + /// they are declared in the static array generated by proc_macro_harness. + pub proc_macros: Vec, + /// Mapping from ident span to path span for paths that don't exist as written, but that + /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. + pub confused_type_with_std_module: FxIndexMap, + pub doc_link_resolutions: FxIndexMap, + pub doc_link_traits_in_scope: FxIndexMap>, + pub all_macro_rules: UnordSet, + pub stripped_cfg_items: Vec, + // Information about delegations which is used when handling recursive delegations + // and ensures easy access to delegation-only `LocalDefId`s. + pub delegation_infos: FxIndexMap, +} + +#[derive(Debug)] +pub struct PerOwnerResolverData<'tcx> { + pub node_id_to_def_id: NodeMap = Default::default(), + /// Whether lifetime elision was successful. + pub lifetime_elision_allowed: bool = false, + /// Resolutions for labels. Maps from NodeId of the break/continue expression to the NodeId of + /// their corresponding blocks or loops. + pub label_res_map: NodeMap = Default::default(), + /// Resolutions for lifetimes. + pub lifetimes_res_map: NodeMap = Default::default(), + + pub trait_map: NodeMap<&'tcx [TraitCandidate<'tcx>]> = Default::default(), + + /// Resolution for import nodes, which have multiple resolutions in different namespaces. + pub import_res: PerNS>> = Default::default(), + /// Lifetime parameters that lowering will have to introduce. + pub extra_lifetime_params_map: NodeMap> = + Default::default(), + + /// The id of the owner + pub id: NodeId, + /// The `DefId` of the owner, can't be found in `node_id_to_def_id`. + pub def_id: LocalDefId, +} + +impl<'tcx> PerOwnerResolverData<'tcx> { + pub fn new(id: NodeId, def_id: LocalDefId) -> PerOwnerResolverData<'tcx> { + PerOwnerResolverData { id, def_id, .. } + } + + /// Obtains resolution for a label with the given `NodeId`. + pub fn get_label_res(&self, id: NodeId) -> Option { + self.label_res_map.get(&id).copied() + } + + /// Obtains resolution for a lifetime with the given `NodeId`. + pub fn get_lifetime_res(&self, id: NodeId) -> Option { + self.lifetimes_res_map.get(&id).copied() + } + + /// Obtain the list of lifetimes parameters to add to an item. + /// + /// Extra lifetime parameters should only be added in places that can appear + /// as a `binder` in `LifetimeRes`. + /// + /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring + /// should appear at the enclosing `PolyTraitRef`. + pub fn extra_lifetime_params(&self, id: NodeId) -> &[(Ident, NodeId, MissingLifetimeKind)] { + self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..]) + } +} + +/// Resolutions that should only be used for lowering. +/// This struct is meant to be consumed by lowering. +#[derive(Debug)] +pub struct ResolverAstLowering<'tcx> { + /// Resolutions for nodes that have a single resolution. + pub partial_res_map: NodeMap, + + pub next_node_id: NodeId, + + pub owners: NodeMap>, + + /// Lints that were emitted by the resolver and early lints. + pub lint_buffer: Steal, + + pub disambiguators: LocalDefIdMap>, +} + +#[derive(Debug, StableHash)] +pub struct DelegationInfo { + // `DefId` (either the resolution at delegation.id or item_id in case of a trait impl) for + // signature resolution, for details see + // https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914. + /// Refers to the next element in a delegation resolution chain. Usually points to the final + /// resolution, as most "chains" are just one step to a trait or an impl. + pub resolution_id: Result, +} + +#[derive(Clone, Copy, Debug, StableHash)] +pub struct MainDefinition { + pub res: Res, + pub is_import: bool, + pub span: Span, +} + +impl MainDefinition { + pub fn opt_fn_def_id(self) -> Option { + if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } + } +} + +// FxIndexMap is necessary because its data ends up in .rmeta files, +// so its iteration order must be consistent. See #159677 for context. +pub type DocLinkResMap = FxIndexMap<(Symbol, Namespace), Option>>; + +/// Fragment of the AST according to "HIR owner" semantics. +/// +/// This is used to map each `LocalDefId` to its content's AST. +/// +/// This type isn't produced by name resolution but it is paired with `ResolverAstLowering` so this +/// is as good a place as any for it. +#[derive(Debug)] +pub enum AstOwner { + /// This definition does not correspond to a HIR owner. + NonOwner, + /// This definition corresponds to a nested `use` tree. + /// The `LocalDefId` points to its HIR owner. + NestedUseTree(LocalDefId), + Crate(Box), + Item(Box), + TraitItem(Box), + ImplItem(Box), + ForeignItem(Box), +} diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index a977fe1ddc07c..beb88e981480d 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -1,4 +1,5 @@ -//! Name resolution for lifetimes and late-bound type and const variables: type declarations. +//! Name resolution for lifetimes and late-bound type and const variables (done by +//! `rustc_hir_analysis`): type declarations. use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 5794a6533bd1d..47cf0473763b4 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -65,7 +65,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{ErrorGuaranteed, catch_fatal_errors}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, DocLinkResMap}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdSet, LocalModId}; use rustc_hir::{ItemLocalId, PreciseCapturingArgKind}; use rustc_index::IndexVec; @@ -79,7 +79,6 @@ use rustc_target::spec::PanicStrategy; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; -use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, SanitizerFnAttrs}; use crate::middle::dead_code::DeadCodeLivenessSummary; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -87,6 +86,9 @@ use crate::middle::deduced_param_attrs::DeducedParamAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; +use crate::middle::resolve::{ + AstOwner, DocLinkResMap, ModChild, ResolverAstLowering, ResolverGlobalCtxt, +}; use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; use crate::middle::stability::DeprecationEntry; use crate::mir::interpret::{ @@ -186,16 +188,16 @@ rustc_queries! { desc { "get the value of an environment variable" } } - query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { + query resolutions(_: ()) -> &'tcx ResolverGlobalCtxt { desc { "getting the resolver outputs" } } query resolver_for_lowering_raw(_: ()) -> ( // Those two fields are consumed by `index_ast`. // We want them to be eventually dropped after lowering. - &'tcx Steal>, + &'tcx Steal>, &'tcx Steal, - &'tcx ty::ResolverGlobalCtxt, + &'tcx ResolverGlobalCtxt, ) { eval_always no_hash @@ -206,8 +208,8 @@ rustc_queries! { // There is only a single `ResolverAstLowering` for all owners. // We want to drop it once the whole HIR has been lowered. // We rely on reference counting to know when all definitions have been stolen. - Arc>, - ast::AstOwner, + Arc>, + AstOwner, )>> { arena_cache eval_always diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5b5656c05f10d..b2e7e619a83ee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -55,8 +55,8 @@ use crate::hir::{ProjectedMaybeOwner, ProjectedOwnerInfo}; use crate::ich::StableHashState; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind}; use crate::lint::emit_lint_base; -use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; +use crate::middle::resolve::{ModChild, ResolverAstLowering}; use crate::middle::resolve_bound_vars; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; @@ -2878,7 +2878,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn resolver_for_lowering( self, - ) -> (&'tcx Steal>, &'tcx Steal) { + ) -> (&'tcx Steal>, &'tcx Steal) { let (resolver, krate, _) = self.resolver_for_lowering_raw(()); (resolver, krate) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3db521dfb5dee..88785d9d7f140 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,21 +28,17 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{ Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx, }; -use rustc_ast::node_id::NodeMap; -use rustc_ast::{self as ast, NodeId}; +use rustc_ast::{self as ast}; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::{self as attr, StrippedCfgItem, find_attr}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_attr_ir::{self as attr, find_attr}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; -use rustc_data_structures::steal::Steal; -use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer}; +use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::PerParentDisambiguatorState; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId}; use rustc_index::bit_set::BitMatrix; use rustc_index::{IndexVec, static_assert_size}; pub use rustc_lint_defs::RegisteredTools; @@ -54,7 +50,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_session::config::OptLevel; use rustc_span::def_id::{LocalModId, ModId}; use rustc_span::hygiene::MacroKind; -use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol}; +use rustc_span::{DUMMY_SP, ExpnKind, Ident, Span, Symbol}; use rustc_target::callconv::FnAbi; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; pub use rustc_type_ir::fast_reject::DeepRejectCtxt; @@ -114,8 +110,6 @@ pub use self::typeck_results::{ UserTypeKind, }; use crate::diagnostics::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; -use crate::metadata::{AmbigModChild, ModChild}; -use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, MirPhase, SourceInfo}; use crate::query::{IntoQueryKey, Providers}; use crate::ty; @@ -171,135 +165,6 @@ mod visit; // Data types -#[derive(Debug, StableHash)] -pub struct ResolverGlobalCtxt { - pub visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, - /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. - pub expn_that_defined: UnordMap, - pub effective_visibilities: EffectiveVisibilities, - // FIXME: This table contains ADTs reachable from macro 2.0. - // Currently, reachability of a definition from a macro is determined by nominal visibility - // (see `compute_effective_visibilities`). This is incorrect and leads to the necessity - // of traversing ADT fields in `rustc_privacy`. Remove this workaround once the - // correct reachability logic is implemented for macros. - pub macro_reachable_adts: FxIndexMap>, - pub extern_crate_map: UnordMap, - pub maybe_unused_trait_imports: FxIndexSet, - pub module_children: LocalDefIdMap>, - pub ambig_module_children: LocalDefIdMap>, - pub glob_map: FxIndexMap>, - pub main_def: Option, - pub trait_impls: FxIndexMap>, - /// A list of proc macro LocalDefIds, written out in the order in which - /// they are declared in the static array generated by proc_macro_harness. - pub proc_macros: Vec, - /// Mapping from ident span to path span for paths that don't exist as written, but that - /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. - pub confused_type_with_std_module: FxIndexMap, - pub doc_link_resolutions: FxIndexMap, - pub doc_link_traits_in_scope: FxIndexMap>, - pub all_macro_rules: UnordSet, - pub stripped_cfg_items: Vec, - // Information about delegations which is used when handling recursive delegations - // and ensures easy access to delegation-only `LocalDefId`s. - pub delegation_infos: FxIndexMap, -} - -#[derive(Debug)] -pub struct PerOwnerResolverData<'tcx> { - pub node_id_to_def_id: NodeMap = Default::default(), - /// Whether lifetime elision was successful. - pub lifetime_elision_allowed: bool = false, - /// Resolutions for labels. Maps from NodeId of the break/continue expression to the NodeId of - /// their corresponding blocks or loops. - pub label_res_map: NodeMap = Default::default(), - /// Resolutions for lifetimes. - pub lifetimes_res_map: NodeMap = Default::default(), - - pub trait_map: NodeMap<&'tcx [hir::TraitCandidate<'tcx>]> = Default::default(), - - /// Resolution for import nodes, which have multiple resolutions in different namespaces. - pub import_res: hir::def::PerNS>> = Default::default(), - /// Lifetime parameters that lowering will have to introduce. - pub extra_lifetime_params_map: NodeMap> = - Default::default(), - - /// The id of the owner - pub id: ast::NodeId, - /// The `DefId` of the owner, can't be found in `node_id_to_def_id`. - pub def_id: LocalDefId, -} - -impl<'tcx> PerOwnerResolverData<'tcx> { - pub fn new(id: ast::NodeId, def_id: LocalDefId) -> PerOwnerResolverData<'tcx> { - PerOwnerResolverData { id, def_id, .. } - } - - /// Obtains resolution for a label with the given `NodeId`. - pub fn get_label_res(&self, id: ast::NodeId) -> Option { - self.label_res_map.get(&id).copied() - } - - /// Obtains resolution for a lifetime with the given `NodeId`. - pub fn get_lifetime_res(&self, id: ast::NodeId) -> Option { - self.lifetimes_res_map.get(&id).copied() - } - - /// Obtain the list of lifetimes parameters to add to an item. - /// - /// Extra lifetime parameters should only be added in places that can appear - /// as a `binder` in `LifetimeRes`. - /// - /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring - /// should appear at the enclosing `PolyTraitRef`. - pub fn extra_lifetime_params( - &self, - id: NodeId, - ) -> &[(Ident, NodeId, hir::MissingLifetimeKind)] { - self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..]) - } -} - -/// Resolutions that should only be used for lowering. -/// This struct is meant to be consumed by lowering. -#[derive(Debug)] -pub struct ResolverAstLowering<'tcx> { - /// Resolutions for nodes that have a single resolution. - pub partial_res_map: NodeMap, - - pub next_node_id: ast::NodeId, - - pub owners: NodeMap>, - - /// Lints that were emitted by the resolver and early lints. - pub lint_buffer: Steal, - - pub disambiguators: LocalDefIdMap>, -} - -#[derive(Debug, StableHash)] -pub struct DelegationInfo { - // `DefId` (either the resolution at delegation.id or item_id in case of a trait impl) for signature resolution, - // for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914 - /// Refers to the next element in a delegation resolution chain. - /// Usually points to the final resolution, as most "chains" are just - /// one step to a trait or an impl. - pub resolution_id: Result, -} - -#[derive(Clone, Copy, Debug, StableHash)] -pub struct MainDefinition { - pub res: Res, - pub is_import: bool, - pub span: Span, -} - -impl MainDefinition { - pub fn opt_fn_def_id(self) -> Option { - if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } - } -} - #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash)] pub struct ImplTraitHeader<'tcx> { pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index c343d9c7078e7..ddd56b384a6a7 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -6,7 +6,8 @@ use rustc_errors::{ Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{MainDefinition, Ty}; +use rustc_middle::middle::resolve::MainDefinition; +use rustc_middle::ty::Ty; use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use crate::check_attr::ProcMacroKind; diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index ddf8bbf764e6e..68be74886a2e4 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -13,8 +13,9 @@ use rustc_crate_store::ExternCrate; use rustc_hir::Target; use rustc_hir::attrs::lang_items::{GenericRequirement, LangItem, LanguageItems}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::middle::resolve::ResolverAstLowering; use rustc_middle::query::Providers; -use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_span::{Span, Symbol, sym}; use crate::diagnostics::{DuplicateLangItem, IncorrectCrateType, IncorrectTarget}; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5fa4db74cb279..88f057c3a6d6d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -23,7 +23,7 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::metadata::{ModChild, Reexport}; +use rustc_middle::middle::resolve::{ModChild, PartialRes, Reexport}; use rustc_middle::ty::{TyCtxtFeed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{CRATE_MOD_ID, ModId}; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 29b1773ddc5ca..4c8000c28f065 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -10,8 +10,9 @@ use rustc_hir::Target; use rustc_hir::def::DefKind; use rustc_hir::def::Namespace::{TypeNS, ValueNS}; use rustc_hir::def_id::LocalDefId; +use rustc_middle::middle::resolve::PerOwnerResolverData; use rustc_middle::span_bug; -use rustc_middle::ty::{PerOwnerResolverData, TyCtxtFeed}; +use rustc_middle::ty::TyCtxtFeed; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index ebcdb8603eccd..520d0849a17d1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -4,8 +4,9 @@ use Determinacy::*; use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PerNS}; use rustc_lint_defs::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; +use rustc_middle::middle::resolve::PartialRes; use rustc_middle::{bug, span_bug}; use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 388073971171b..1cda9b9139028 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -8,14 +8,14 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, BufferedEarlyLint, Diagnostic}; use rustc_expand::base::SyntaxExtensionKind; -use rustc_hir::def::{self, DefKind, PartialRes}; +use rustc_hir::def::{self, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_lint_defs::LintId; use rustc_lint_defs::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; -use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; +use rustc_middle::middle::resolve::{AmbigModChild, ModChild, PartialRes, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::Visibility; use rustc_session::diagnostics::feature_err; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 396db754f7c96..b1e871339a607 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -25,12 +25,13 @@ use rustc_errors::{ StashKey, Suggestions, elided_lifetime_in_path_suggestion, pluralize, }; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_hir::def::{CtorKind, DefKind, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_lint_defs::builtin::{ELIDED_LIFETIMES_IN_PATHS, UNUSED_LABELS}; +use rustc_middle::middle::resolve::{DelegationInfo, LifetimeRes, PartialRes}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility}; +use rustc_middle::ty::{AssocTag, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::ResolveDocLinks; use rustc_session::diagnostics::feature_err; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f5e684cb81631..16febb373e805 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -53,22 +53,20 @@ use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind} use rustc_feature::{BUILTIN_ATTRIBUTES, Features}; use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{ - self, CtorOf, DefKind, DocLinkResMap, MacroKinds, NonMacroAttrKind, PartialRes, PerNS, -}; +use rustc_hir::def::{self, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::{PerParentDisambiguatorState, PerParentDisambiguatorsMap}; use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_lint_defs::builtin::PRIVATE_MACRO_USE; use rustc_metadata::creader::CStore; -use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::query::Providers; -use rustc_middle::ty::{ - self, DelegationInfo, MainDefinition, PerOwnerResolverData, RegisteredTools, - ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, +use rustc_middle::middle::resolve::{ + AmbigModChild, DelegationInfo, DocLinkResMap, MainDefinition, ModChild, PartialRes, + PerOwnerResolverData, Reexport, ResolverAstLowering, ResolverGlobalCtxt, }; +use rustc_middle::query::Providers; +use rustc_middle::ty::{self, RegisteredTools, TyCtxt, TyCtxtFeed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{LocalModId, ModId}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; @@ -1993,7 +1991,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { stripped_cfg_items, delegation_infos: self.delegation_infos, }; - let ast_lowering = ty::ResolverAstLowering { + let ast_lowering = ResolverAstLowering { partial_res_map: self.partial_res_map, next_node_id: self.next_node_id, owners: self.owners, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 784a80ef02cd2..b6cd31a16eaaf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{PredicateOrigin, find_attr}; use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; -use rustc_middle::metadata::Reexport; +use rustc_middle::middle::resolve::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{ self, AdtKind, GenericArgsRef, RegionExt, Ty, TyCtxt, TypeVisitableExt, TypingMode, diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 35e254c754d68..c04438d69007b 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -3,8 +3,9 @@ use std::ops::Range; use rustc_ast::NodeId; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, SuggestionStyle}; use rustc_hir::HirId; -use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; +use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_lint::Applicability; +use rustc_middle::middle::resolve::DocLinkResMap; use rustc_resolve::rustdoc::pulldown_cmark::{ BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag, }; From b61efecae3c0dc4360761fa6b8ab70ebc989b3e0 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:01:45 +0200 Subject: [PATCH 25/40] type system const items via direct rhs --- compiler/rustc_ast_lowering/src/lib.rs | 48 +++++++++++++----- .../src/const_eval/eval_queries.rs | 11 +++- compiler/rustc_hir/src/hir.rs | 6 +-- compiler/rustc_hir/src/intravisit.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 5 +- .../src/check/compare_impl_item.rs | 13 ++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 21 +++----- compiler/rustc_hir_analysis/src/collect.rs | 31 ++++++------ .../src/collect/clauses_of.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 50 ++++++++++++------- .../src/hir_ty_lowering/bounds.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 16 +----- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/queries.rs | 14 ++++-- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/ty/assoc.rs | 13 ++--- compiler/rustc_middle/src/ty/context.rs | 25 +++++++--- .../src/ty/context/impl_interner.rs | 23 +++++++-- .../src/builder/expr/as_constant.rs | 13 ++++- compiler/rustc_mir_build/src/thir/cx/mod.rs | 9 +++- .../src/thir/pattern/const_to_pat.rs | 17 +++++-- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../src/solve/normalizes_to.rs | 9 ++-- .../src/solve/project_goals/free_alias.rs | 6 ++- .../src/solve/project_goals/inherent.rs | 7 ++- compiler/rustc_passes/src/reachable.rs | 2 +- .../src/traits/normalize.rs | 6 +-- .../src/traits/project.rs | 20 +++++++- .../rustc_trait_selection/src/traits/wf.rs | 3 +- .../src/normalize_projection_ty.rs | 5 +- compiler/rustc_ty_utils/src/assoc.rs | 12 ++--- compiler/rustc_type_ir/src/const_kind.rs | 10 +--- compiler/rustc_type_ir/src/interner.rs | 7 ++- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- ...-on-failed-eval-with-vars-fail.next.stderr | 16 +++--- ...s-on-failed-eval-with-vars-fail.old.stderr | 2 +- ...ambiguous-on-failed-eval-with-vars-fail.rs | 5 +- tests/ui/const-generics/gca/assoc-const.rs | 22 ++++++++ .../gca/non-type-equality-fail.rs | 9 ++-- .../gca/non-type-equality-fail.stderr | 18 +++---- .../gca/non-type-equality-ok.rs | 2 + .../gca/wf-inherentimpl.old.stderr | 2 +- .../ui/const-generics/gca/wf-inherentimpl.rs | 3 +- 48 files changed, 307 insertions(+), 197 deletions(-) create mode 100644 tests/ui/const-generics/gca/assoc-const.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5b76606d101bc..a4c6769e91f83 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2672,19 +2672,41 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ConstItemRhs<'hir> { match (body, kind) { (body, ConstItemKind::Body) => { - hir::ConstItemRhs::Body(self.lower_const_body(span, body.as_deref())) - } - (Some(body), ConstItemKind::TypeConst) => { - hir::ConstItemRhs::TypeConst(self.arena.alloc( - match self.can_lower_expr_to_const_arg_direct( - &body, - DirectConstArgContext::MacrolessMinGenericConstArgs, - ) { - Ok(()) => self.lower_expr_to_const_arg_direct(&body, None), - Err(err) => err.emit(self), - }, - )) + let is_direct = |body| { + if self.tcx.features().macroless_generic_const_args() { + self.can_lower_expr_to_const_arg_direct( + body, + DirectConstArgContext::MacrolessMinGenericConstArgs, + ) + .is_ok() + } else { + // do not check can_lower_expr_to_const_arg_direct, but rather just + // ExprKind::DirectConstArg, because we don't want e.g. + // `impl { const C: u8 = N; }` to be a direct-rhs const + matches!(body, Expr { kind: ExprKind::DirectConstArg(_), .. }) + } + }; + // N.B.: the feature gate for this is generic_const_args, not min_generic_const_args + if self.tcx.features().generic_const_args() + && let Some(body) = body + && is_direct(body) + { + hir::ConstItemRhs::Direct( + self.arena.alloc(self.lower_expr_to_const_arg_direct(&body, None)), + ) + } else { + hir::ConstItemRhs::Body(self.lower_const_body(span, body.as_deref())) + } } + (Some(body), ConstItemKind::TypeConst) => hir::ConstItemRhs::Direct(self.arena.alloc( + match self.can_lower_expr_to_const_arg_direct( + &body, + DirectConstArgContext::MacrolessMinGenericConstArgs, + ) { + Ok(()) => self.lower_expr_to_const_arg_direct(&body, None), + Err(err) => err.emit(self), + }, + )), (None, ConstItemKind::TypeConst) => { let const_arg = ConstArg { hir_id: self.next_id(), @@ -2693,7 +2715,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), span: DUMMY_SP, }; - hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg)) + hir::ConstItemRhs::Direct(self.arena.alloc(const_arg)) } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 912be902b46f7..c823da68b65bd 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -440,8 +440,15 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( typing_env: ty::TypingEnv<'tcx>, ) -> Result { let def = cid.instance.def.def_id(); - // `type const` don't have bodys - debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def); + // directly represented consts don't have bodies + if cfg!(debug_assertions) + && matches!(tcx.def_kind(def), DefKind::Const { .. } | DefKind::AssocConst { .. }) + { + debug_assert!( + tcx.const_of_item(def).is_none(), + "CTFE tried to evaluate directly represented const item: {def:?}" + ); + } let is_static = tcx.is_static(def); let mut ecx = InterpCx::new( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fb4b61e9f4875..e9b519ae2a558 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -416,21 +416,21 @@ impl<'hir> PathSegment<'hir> { #[derive(Clone, Copy, Debug, StableHash)] pub enum ConstItemRhs<'hir> { Body(BodyId), - TypeConst(&'hir ConstArg<'hir>), + Direct(&'hir ConstArg<'hir>), } impl<'hir> ConstItemRhs<'hir> { pub fn hir_id(&self) -> HirId { match self { ConstItemRhs::Body(body_id) => body_id.hir_id, - ConstItemRhs::TypeConst(ct_arg) => ct_arg.hir_id, + ConstItemRhs::Direct(ct_arg) => ct_arg.hir_id, } } pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span { match self { ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span, - ConstItemRhs::TypeConst(ct_arg) => ct_arg.span, + ConstItemRhs::Direct(ct_arg) => ct_arg.span, } } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 811dccc4a0ad9..db0f685b9d5a6 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1082,7 +1082,7 @@ pub fn walk_const_item_rhs<'v, V: Visitor<'v>>( ) -> V::Result { match ct_rhs { ConstItemRhs::Body(body_id) => visitor.visit_nested_body(body_id), - ConstItemRhs::TypeConst(const_arg) => visitor.visit_const_arg_unambig(const_arg), + ConstItemRhs::Direct(const_arg) => visitor.visit_const_arg_unambig(const_arg), } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1895f586df2f0..d5bc834b831c7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -953,10 +953,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.require_lang_item(LangItem::Sized, ty_span), ); check_where_clauses(wfcx, def_id); - - if tcx.is_type_const(def_id) { - wfcheck::check_type_const(wfcx, def_id, ty, true)?; - } + wfcheck::check_const_item(wfcx, def_id, ty); Ok(()) })); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e5d26cf72f9a5..4aebe60182333 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2157,12 +2157,10 @@ fn compare_type_const<'tcx>( impl_const_item: ty::AssocItem, trait_const_item: ty::AssocItem, ) -> Result<(), ErrorGuaranteed> { - let impl_is_type_const = tcx.is_type_const(impl_const_item.def_id); - let trait_type_const_span = tcx.type_const_span(trait_const_item.def_id); + let impl_is_type_const = tcx.is_type_const_syntax(impl_const_item.def_id); + let trait_is_type_const = tcx.is_type_const_syntax(trait_const_item.def_id); - if let Some(trait_type_const_span) = trait_type_const_span - && !impl_is_type_const - { + if trait_is_type_const && !impl_is_type_const { return Err(tcx .dcx() .struct_span_err( @@ -2170,10 +2168,7 @@ fn compare_type_const<'tcx>( "implementation of a `type const` must also be marked as `type const`", ) .with_span_note( - MultiSpan::from_spans(vec![ - tcx.def_span(trait_const_item.def_id), - trait_type_const_span, - ]), + tcx.def_span(trait_const_item.def_id), "trait declaration of const is marked as `type const`", ) .emit()); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4b95f1e82cd9a..f0a5db377f6bc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -929,13 +929,9 @@ pub(crate) fn check_associated_item( let ty = tcx.type_of(def_id).instantiate_identity(); let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); + check_const_item(wfcx, def_id, ty); - let has_value = item.defaultness(tcx).has_value(); - if tcx.is_type_const(def_id) { - check_type_const(wfcx, def_id, ty, has_value)?; - } - - if has_value { + if item.defaultness(tcx).has_value() { let code = ObligationCauseCode::SizedConstOrStatic; wfcx.register_bound( ObligationCause::new(span, def_id, code), @@ -1264,17 +1260,17 @@ pub(crate) fn check_static_item<'tcx>( }) } +/// Runs checks common to both free consts and associated consts #[instrument(level = "debug", skip(wfcx))] -pub(super) fn check_type_const<'tcx>( +pub(super) fn check_const_item<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id: LocalDefId, item_ty: Ty<'tcx>, - has_value: bool, -) -> Result<(), ErrorGuaranteed> { +) { let tcx = wfcx.tcx(); let span = tcx.def_span(def_id); - if !tcx.features().const_param_ty_unchecked() { + if tcx.is_direct_const(def_id.into()) && !tcx.features().const_param_ty_unchecked() { wfcx.register_bound( ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(item_ty)), wfcx.param_env, @@ -1283,8 +1279,8 @@ pub(super) fn check_type_const<'tcx>( ); } - if has_value { - let raw_ct = tcx.const_of_item(def_id).instantiate_identity(); + if let Some(direct_rhs) = tcx.const_of_item(def_id) { + let raw_ct = direct_rhs.instantiate_identity(); let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct); wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into()); @@ -1295,7 +1291,6 @@ pub(super) fn check_type_const<'tcx>( ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(norm_ct, item_ty)), )); } - Ok(()) } #[instrument(level = "debug", skip(tcx, impl_))] diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 248e7aa583a19..0c2b33917cc98 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1804,25 +1804,24 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin fn const_of_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Const<'tcx>> { +) -> Option>> { let ct_rhs = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => *ct, - hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(_, ct), .. }) => { - ct.expect("no default value for trait assoc const") - } - hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct, - _ => { - span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item") + hir::Node::Item(&hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => ct, + hir::Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Const(_, ct), .. + }) => ct?, + hir::Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => ct, + node => { + span_bug!( + tcx.def_span(def_id), + "`const_of_item` expected a const or assoc const item, got {node:?}" + ) } }; let ct_arg = match ct_rhs { - hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg, + hir::ConstItemRhs::Direct(ct_arg) => ct_arg, hir::ConstItemRhs::Body(_) => { - let e = tcx.dcx().span_delayed_bug( - tcx.def_span(def_id), - "cannot call const_of_item on a non-type_const", - ); - return ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e)); + return None; } }; let icx = ItemCtxt::new(tcx, def_id); @@ -1834,8 +1833,8 @@ fn const_of_item<'tcx>( if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { - ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e)) + Some(ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e))) } else { - ty::EarlyBinder::bind(tcx, ct) + Some(ty::EarlyBinder::bind(tcx, ct)) } } diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index 488b9a09e6106..00f3874e4707b 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -444,7 +444,7 @@ fn const_evaluatable_clauses_of<'tcx>( } // Skip type consts as mGCA doesn't support evaluatable clauses. - if alias_const.kind.is_type_const(self.tcx) { + if alias_const.kind.is_direct_const(self.tcx) { return; } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 45254aa23896d..6ebd38195ffbe 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -87,10 +87,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ TraitItemKind::Const(ty, rhs) => rhs .and_then(|rhs| { ty.is_suggestable_infer_ty().then(|| { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), item.ident, @@ -109,10 +113,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ImplItemKind::Fn(_, _) => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), ImplItemKind::Const(ty, rhs) => { if ty.is_suggestable_infer_ty() { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), item.ident, @@ -137,7 +145,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ infer_placeholder_type( icx.lowerer(), def_id, - body_id.hir_id, + Some(body_id.hir_id), ty.span, tcx.hir_body(body_id).value.span, ident, @@ -157,10 +165,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } ItemKind::Const(ident, _, ty, rhs) => { if ty.is_suggestable_infer_ty() { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), ident, @@ -431,28 +443,28 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S fn infer_placeholder_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, - hir_id: HirId, + hir_body_id: Option, ty_span: Span, body_span: Span, item_ident: Ident, kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - // If the type is omitted on a `type const` we can't run - // type check on since that requires the const have a body - // which `type const`s don't. - let ty = if tcx.is_type_const(def_id.to_def_id()) { - if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { - tcx.type_of(trait_item_def_id).instantiate_identity().skip_norm_wip() - } else { - Ty::new_error_with_message( - tcx, - ty_span, - "constant with `type const` requires an explicit type", - ) + // If the type is omitted on const with `ConstItemRhs::Direct`, we can't run type check on it, + // since that requires the const have a body, i.e. `ConstItemRhs::Body`. + let ty = match hir_body_id { + Some(hir_id) => tcx.typeck(def_id).node_type(hir_id), + None => { + if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { + tcx.type_of(trait_item_def_id).instantiate_identity().skip_norm_wip() + } else { + Ty::new_error_with_message( + tcx, + ty_span, + "directly represented const requires an explicit type", + ) + } } - } else { - tcx.typeck(def_id).node_type(hir_id) }; // If this came from a free `const` or `static mut?` item, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9fde34f473205..219637ba4f16f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -557,7 +557,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); if let ty::AssocTag::Const = assoc_tag - && !self.tcx().is_type_const(assoc_item.def_id) + && !self.tcx().is_direct_const(assoc_item.def_id) && !tcx.features().generic_const_args() { if tcx.features().min_generic_const_args() { 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 cfff8d1768f0e..e8bb4807f3835 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3153,7 +3153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - if tcx.is_type_const(def_id) || tcx.features().generic_const_args() { + if tcx.is_type_const_syntax(def_id) || tcx.features().generic_const_args() { Ok(()) } else { let mut err = self.dcx().struct_span_err( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 41f98e2fb40c0..20ef75244bb4e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -174,7 +174,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } DefKind::Const { .. } if !tcx.generics_of(item_def_id).own_requires_monomorphization() - && !tcx.is_type_const(item_def_id) => + && tcx.const_of_item(item_def_id).is_none() => { // FIXME(generic_const_items): Passing empty instead of identity args is fishy but // seems to be fine for now. Revisit this! diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a949f8e505fa7..d56c1481a3c27 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1166,7 +1166,7 @@ impl<'a> State<'a> { fn print_const_item_rhs(&mut self, ct_rhs: hir::ConstItemRhs<'_>) { match ct_rhs { hir::ConstItemRhs::Body(body_id) => self.ann.nested(self, Nested::Body(body_id)), - hir::ConstItemRhs::TypeConst(const_arg) => self.print_const_arg(const_arg), + hir::ConstItemRhs::Direct(const_arg) => self.print_const_arg(const_arg), } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1d9dade66a544..f55783e60da0c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1382,20 +1382,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_const_of_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool { - // AssocConst ==> assoc item has value - tcx.is_type_const(def_id) - && (!matches!(def_kind, DefKind::AssocConst { .. }) || assoc_item_has_value(tcx, def_id)) -} - -fn assoc_item_has_value<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - let assoc_item = tcx.associated_item(def_id); - match assoc_item.container { - ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, - ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), - } -} - impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; @@ -1632,7 +1618,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::AnonConst = def_kind { record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); } - if should_encode_const_of_item(self.tcx, def_id, def_kind) { + if let DefKind::Const { .. } | DefKind::AssocConst { .. } = def_kind { record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id)); } if tcx.impl_method_has_trait_impl_trait_tys(def_id) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 064d906293ae8..938cd2e956c13 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -480,7 +480,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, - const_of_item: Table>>>, + const_of_item: Table>>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, live_args_for_alias_from_outlives_bounds: Table>>>>>, args_known_to_outlive_alias_params: Table, Vec>)>>>>, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 5794a6533bd1d..80b73038481d3 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -279,14 +279,22 @@ rustc_queries! { separate_provide_extern } - /// Returns the const of the RHS of a (free or assoc) const item, if it is a `type const`. + /// Returns the const of the RHS of a (free or assoc) const item, if it is a `type const`, or if + /// it is a directly represented `const` (i.e. a const with a `direct_const_arg!` RHS, or a + /// const that `feature(macroless_generic_const_args)` has decided is direct). /// /// When a const item is used in a type-level expression, like in equality for an assoc const /// projection, this allows us to retrieve the typesystem-appropriate representation of the /// const value. /// - /// This query will ICE if given a const that is not marked with `type const`. - query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + /// Returns `None` if the constant does not have a directly represented RHS. This does not + /// necessarily mean the constant is invalid to use in the type system, as is the case for a + /// `type const` in a trait definition without a RHS. + /// + /// # Panics + /// + /// This query will panic if the given definition isn't a const item (free or associated const). + query const_of_item(def_id: DefId) -> Option>> { desc { "computing the type-level value for `{}`", tcx.def_path_str(def_id) } cache_on_disk separate_provide_extern diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 23c02ffcb09c4..93d4c59e75c00 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -195,6 +195,7 @@ impl_erasable_for_types_with_no_type_params! { Option, Option, Option>>, + Option>>, Option>, Option, Result<&'_ TokenStream, ()>, diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 279a3658109bc..8eee87bdd07ca 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -138,17 +138,12 @@ impl AssocItem { self.kind.as_def_kind() } - pub fn is_type_const(&self) -> bool { - matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. }) - } - /// Whether this associated item can be constrained with an equality binding. pub fn can_have_equality_constraint(&self, tcx: TyCtxt<'_>) -> bool { match self.kind { ty::AssocKind::Type { .. } => true, - ty::AssocKind::Const { is_type_const: true, .. } => true, - ty::AssocKind::Const { is_type_const: false, .. } => { - tcx.features().generic_const_args() + ty::AssocKind::Const { .. } => { + tcx.features().generic_const_args() || tcx.is_direct_const(self.def_id) } ty::AssocKind::Fn { .. } => false, } @@ -209,9 +204,7 @@ impl AssocKind { pub fn as_def_kind(&self) -> DefKind { match self { - Self::Const { is_type_const, .. } => { - DefKind::AssocConst { is_type_const: *is_type_const } - } + &Self::Const { is_type_const, .. } => DefKind::AssocConst { is_type_const }, Self::Fn { .. } => DefKind::AssocFn, Self::Type { .. } => DefKind::AssocTy, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5b5656c05f10d..6e4c94f860170 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1029,15 +1029,26 @@ impl<'tcx> TyCtxt<'tcx> { self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace) } - pub fn type_const_span(self, def_id: DefId) -> Option { - if !self.is_type_const(def_id) { - return None; - } - Some(self.def_span(def_id)) + /// Returns true if the const is guaranteed to have a directly represented RHS. This is either + /// because it has a directly represented RHS, or is a trait definition that is marked as + /// requiring its implementation to have a directly represented RHS. + /// + /// Note: Be very careful with using this method - under `generic_const_args`, a trait can + /// declare a regular const, but an `impl` could implement it with a directly represented const + /// (a la refinement). This method would return false in such a case. + pub fn is_direct_const(self, def_id: DefId) -> bool { + debug_assert_matches!( + self.def_kind(def_id), + DefKind::Const { .. } | DefKind::AssocConst { .. } + ); + self.is_type_const_syntax(def_id) || self.const_of_item(def_id).is_some() } - /// Check if the given `def_id` is a `type const` (mgca) - pub fn is_type_const(self, def_id: impl IntoQueryKey) -> bool { + /// Check if the given `def_id` is declared with `type const` syntax (mgca) + /// + /// This is NOT the same as whether the `def_id` can be represented in/used by the type system. + /// For that, you probably want to ask `is_direct_const()` or `const_of_item().is_some()`. + pub fn is_type_const_syntax(self, def_id: impl IntoQueryKey) -> bool { let def_id = def_id.into_query_key(); match self.def_kind(def_id) { DefKind::Const { is_type_const } | DefKind::AssocConst { is_type_const } => { diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 74327278dbca6..fa6ea5f1a70dd 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -186,11 +186,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } - fn is_type_const(self, def_id: DefId) -> bool { - self.is_type_const(def_id) + fn is_direct_const(self, alias: ty::AliasConstKind<'tcx>) -> bool { + match alias { + ty::AliasConstKind::Projection { def_id } + | ty::AliasConstKind::InherentSelf { def_id } + | ty::AliasConstKind::InherentImpl { def_id } + | ty::AliasConstKind::Free { def_id } => self.is_direct_const(def_id), + ty::AliasConstKind::Anon { .. } => false, + } } - fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - self.const_of_item(def_id) + fn const_of_item( + self, + alias: ty::AliasConstKind<'tcx>, + ) -> Option>> { + match alias { + ty::AliasConstKind::Projection { def_id } + | ty::AliasConstKind::InherentSelf { def_id } + | ty::AliasConstKind::InherentImpl { def_id } + | ty::AliasConstKind::Free { def_id } => self.const_of_item(def_id), + ty::AliasConstKind::Anon { .. } => None, + } } fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind { self.anon_const_kind(def_id) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 5996073241e2c..830fdc5d75573 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -3,6 +3,7 @@ use rustc_abi::Size; use rustc_ast as ast; use rustc_hir::attrs::lang_items::LangItem; +use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -71,7 +72,17 @@ pub(crate) fn as_constant_inner<'tcx>( } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - if tcx.is_type_const(def_id) { + // Under generic_const_args, `def_id` might be a regular const declared in a trait, but + // is `impl`d as a directly represented const. We do not know whether it is here, so we + // must use type system normalization for all consts under generic_const_args. + // FIXME(generic_const_args): there's a lot to consider here! `Const::Ty` uses valtrees + // and `Const::Unevaluated` does not, we should revisit this before stabilization. + if tcx.features().generic_const_args() + || matches!( + tcx.def_kind(def_id), + DefKind::Const { .. } | DefKind::AssocConst { .. } + ) && tcx.is_direct_const(def_id) + { let uneval = ty::AliasConst::new( tcx, ty::AliasConstKind::new_from_def_id( diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index aad87a99c0036..31a760cc59829 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -17,7 +17,14 @@ pub(crate) fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: LocalDefId, ) -> Result<(&'tcx Steal>, ExprId), ErrorGuaranteed> { - debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const"); + if cfg!(debug_assertions) + && matches!(tcx.def_kind(owner_def), DefKind::Const { .. } | DefKind::AssocConst { .. }) + { + debug_assert!( + tcx.const_of_item(owner_def.to_def_id()).is_none(), + "thir_body queried for directly represented const item: {owner_def:?}" + ); + } let body = tcx.hir_body_owned_by(owner_def); let mut cx: ThirBuildCx<'tcx> = ThirBuildCx::new(tcx, owner_def); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 86387f5caf325..7c6885bf8020c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -136,11 +136,18 @@ impl<'tcx> ConstToPat<'tcx> { return self.mk_err(err, ty); }; - // FIXME(gca): This will become insufficient once associated constants can be - // implemented as `type` consts (project-const-generics#76). At that point it'll - // become necessary to just use type system normalization for all const patterns - // but that's not yet possible. - let const_value = if alias_const.kind.is_type_const(self.tcx) { + // Under generic_const_args, `alias_const` might be a regular const declared in a trait, but + // is `impl`d as a directly represented const. We do not know whether it is here, so we must + // use type system normalization for all consts under generic_const_args. + // + // We probably want to always use type system normalization on stable too, but that would be + // a breaking change (in addition to needing significant improvements to diagnostics), so + // right now, we limit this to just generic_const_args. + // + // See: https://github.com/rust-lang/project-const-generics/issues/105 + let const_value = if self.tcx.features().generic_const_args() + || alias_const.kind.is_direct_const(self.tcx) + { let Ok(normalize) = self .tcx .try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c)) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b7813992db5bf..4ee1abe4a1ff4 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1663,7 +1663,7 @@ impl<'v> RootCollector<'_, 'v> { let def_id = id.owner_id.to_def_id(); // Type Consts don't have bodies to evaluate // nor do they make sense as a static. - if self.tcx.is_type_const(def_id) { + if self.tcx.const_of_item(def_id).is_some() { // FIXME(mgca): Is this actually what we want? We may want to // normalize to a ValTree then convert to a const allocation and // collect that? diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 75f15623a9ba7..cb878f2c54878 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -435,16 +435,17 @@ where } // Finally we construct the actual value of the associated type. - let term = match goal.predicate.alias.kind { + let term = match target_item_kind { ty::AliasTermKind::ProjectionTy { .. } => { let t = cx.type_of(target_item_def_id).instantiate(cx, target_args); let t = ecx.normalize(GoalSource::Misc, goal.param_env, t)?; t.into() } - ty::AliasTermKind::ProjectionConst { .. } - if cx.is_type_const(target_item_def_id) => + ty::AliasTermKind::ProjectionConst { def_id } + if let Some(c) = + cx.const_of_item(ty::AliasConstKind::Projection { def_id }) => { - let c = cx.const_of_item(target_item_def_id).instantiate(cx, target_args); + let c = c.instantiate(cx, target_args); let c = ecx.normalize(GoalSource::Misc, goal.param_env, c)?; c.into() } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs index efc630a106ee3..4481e1bc144ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs @@ -37,8 +37,10 @@ where let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; free.into() } - ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id.into()) => { - let free = cx.const_of_item(def_id.into()).instantiate(cx, free_alias.args); + ty::AliasTermKind::FreeConst { def_id } + if let Some(free) = cx.const_of_item(ty::AliasConstKind::Free { def_id }) => + { + let free = free.instantiate(cx, free_alias.args); let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; free.into() diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs index 20c0564b0eeba..d519d1e538f1a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs @@ -48,8 +48,11 @@ where let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; inherent.into() } - ty::AliasTermKind::InherentConstImpl { def_id } if cx.is_type_const(def_id.into()) => { - let inherent = cx.const_of_item(def_id.into()).instantiate(cx, inherent_args); + ty::AliasTermKind::InherentConstImpl { def_id } + if let Some(inherent) = + cx.const_of_item(ty::AliasConstKind::InherentImpl { def_id }) => + { + let inherent = inherent.instantiate(cx, inherent_args); let normalized_ct = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; let normalized = normalized_ct.into(); let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index e5f5b67912c75..de0d0a4f8a4f2 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -209,7 +209,7 @@ impl<'tcx> ReachableContext<'tcx> { } } // For `type const` we want to evaluate the RHS. - hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::TypeConst(_)) => { + hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::Direct(_)) => { self.visit_const_item_rhs(init); } hir::ItemKind::Const(_, _, _, init) => { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 0d22ca4973511..56df5d917e108 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -349,9 +349,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { .fold_with(self) .into() } else { - infcx - .tcx - .const_of_item(def_id) + project::const_of_item_or_delayed_bug(infcx.tcx, def_id) .instantiate(infcx.tcx, free.args) .skip_norm_wip() .fold_with(self) @@ -469,7 +467,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx if tcx.features().generic_const_exprs() // Normalize type_const items even with feature `generic_const_exprs`. - && !matches!(ct.kind(), ty::ConstKind::Alias(_, alias_const) if alias_const.kind.is_type_const(tcx)) + && !matches!(ct.kind(), ty::ConstKind::Alias(_, alias_const) if alias_const.kind.is_direct_const(tcx)) || !needs_normalization(self.selcx.infcx, &ct) { return ct; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9d0daa3a8672b..f3504e96965e8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -505,6 +505,22 @@ fn push_const_arg_has_type_obligation<'tcx>( } } +/// The old solver does not support references to non-type-consts. +/// Emit a delayed bug if there is a type system reference to a non type const, as this should have +/// already errored elsewhere. +pub fn const_of_item_or_delayed_bug<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + tcx.const_of_item(def_id).unwrap_or_else(|| { + let e = tcx.dcx().span_delayed_bug( + tcx.def_span(def_id), + "encountered regular consts in the old solver's const normalization", + ); + ty::EarlyBinder::bind(tcx, ty::Const::new_error(tcx, e)) + }) +} + /// Confirm and normalize the given inherent projection. // FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] @@ -565,7 +581,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let term = if alias_term.kind.is_type() { tcx.type_of(def_id).instantiate(tcx, args).map(Into::into) } else { - tcx.const_of_item(def_id).instantiate(tcx, args).map(Into::into) + const_of_item_or_delayed_bug(tcx, def_id).instantiate(tcx, args).map(Into::into) }; let term = selcx.infcx.resolve_vars_if_possible(term); @@ -2115,7 +2131,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term = if obligation.predicate.kind.is_type() { tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) + const_of_item_or_delayed_bug(tcx, assoc_term.item.def_id).map_bound(|ct| ct.into()) }; assoc_term_own_obligations(selcx, obligation, &mut nested); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fc16b6d44c310..5fc9e57795b72 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1088,7 +1088,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::ConstKind::Alias(_, alias_const) => { if !c.has_escaping_bound_vars() { // Skip type consts as mGCA doesn't support evaluatable clauses - if !alias_const.kind.is_type_const(tcx) && !tcx.features().generic_const_args() + if !alias_const.kind.is_direct_const(tcx) + && !tcx.features().generic_const_args() { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 03dff745210d6..c3fe949d29d64 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -108,7 +108,10 @@ fn normalize_canonicalized_free_alias<'tcx>( let normalized_term: ty::Term<'tcx> = if goal.kind.is_type() { tcx.type_of(def_id).instantiate(tcx, goal.args).skip_norm_wip().into() } else { - tcx.const_of_item(def_id).instantiate(tcx, goal.args).skip_norm_wip().into() + traits::project::const_of_item_or_delayed_bug(tcx, def_id) + .instantiate(tcx, goal.args) + .skip_norm_wip() + .into() }; ocx.register_obligations(const_arg_has_type_obligation( tcx, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index de94087498c75..ea58041a12b77 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind}; +use rustc_hir::{self as hir, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -89,7 +89,7 @@ fn associated_item_from_trait_item( let name = trait_item.ident.name; let kind = match trait_item.kind { hir::TraitItemKind::Const(_, _) => { - ty::AssocKind::Const { name, is_type_const: tcx.is_type_const(owner_id.def_id) } + ty::AssocKind::Const { name, is_type_const: tcx.is_type_const_syntax(owner_id.def_id) } } hir::TraitItemKind::Fn { .. } => { ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } @@ -106,13 +106,13 @@ fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_> let owner_id = impl_item.owner_id; let name = impl_item.ident.name; let kind = match impl_item.kind { - hir::ImplItemKind::Const(_, rhs) => { - ty::AssocKind::Const { name, is_type_const: matches!(rhs, ConstItemRhs::TypeConst(_)) } + hir::ImplItemKind::Const(..) => { + ty::AssocKind::Const { name, is_type_const: tcx.is_type_const_syntax(owner_id.def_id) } } - hir::ImplItemKind::Fn { .. } => { + hir::ImplItemKind::Fn(..) => { ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } } - hir::ImplItemKind::Type { .. } => { + hir::ImplItemKind::Type(..) => { ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) } } }; diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 26a4edccd0134..36cef1c13eb29 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -160,14 +160,8 @@ impl AliasConstKind { interner.alias_const_kind_from_def_id(def_id, inherent_args) } - pub fn is_type_const(self, interner: I) -> bool { - match self { - AliasConstKind::Projection { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::InherentSelf { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::InherentImpl { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::Free { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::Anon { def_id } => interner.is_type_const(def_id.into()), - } + pub fn is_direct_const(self, interner: I) -> bool { + interner.is_direct_const(self) } pub fn def_span(self, interner: I) -> I::Span { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1dfb34d94c0fc..282ec24246d16 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -266,8 +266,11 @@ pub trait Interner: self, def_id: Self::LocalOpaqueTyId, ) -> ty::EarlyBinder; - fn is_type_const(self, def_id: Self::DefId) -> bool; - fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; + fn is_direct_const(self, alias: ty::AliasConstKind) -> bool; + fn const_of_item( + self, + alias: ty::AliasConstKind, + ) -> Option>; fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; fn def_span(self, def_id: Self::DefId) -> Self::Span; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 784a80ef02cd2..94f2e2a04a14b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -354,7 +354,7 @@ pub(crate) fn clean_const_item_rhs<'tcx>( ) -> ConstantKind { match ct_rhs { hir::ConstItemRhs::Body(body) => ConstantKind::Local { def_id: parent, body }, - hir::ConstItemRhs::TypeConst(ct) => clean_const(ct), + hir::ConstItemRhs::Direct(ct) => clean_const(ct), } } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 6230349651026..919b9b8ba8368 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -965,7 +965,7 @@ fn get_const_hir_value<'tcx>( }; match ct_rhs { ConstItemRhs::Body(body_id) => Some((tcx.typeck(did), tcx.hir_body(body_id).value)), - ConstItemRhs::TypeConst(ct_arg) => match ct_arg.kind { + ConstItemRhs::Direct(ct_arg) => match ct_arg.kind { ConstArgKind::Anon(anon_const) => Some((tcx.typeck(did), tcx.hir_body(anon_const.body).value)), _ => None, }, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index bcdc7754da6fa..8ca6d08e325f7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1187,7 +1187,7 @@ pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: Syntax pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx>) -> Option<&'tcx Expr<'tcx>> { match ct_rhs { ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), - ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { + ConstItemRhs::Direct(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) | ConstArgKind::Tup(..) diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr index 366711e6d43c7..3b53adb07a2b9 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -1,13 +1,13 @@ error[E0284]: type annotations needed for `([(); _], [(); 10])` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:32:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:31:9 | LL | let (mut arr, mut arr_with_weird_len) = free(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point | note: required by a const generic parameter in `free` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:27:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:26:9 | -LL | fn free() -> ([(); N], [(); FREE::]) { +LL | fn free() -> ([(); N], [(); core::direct_const_arg!(FREE::)]) { | ^^^^^^^^^^^^^^ required by this const generic parameter in `free` help: consider giving this pattern a type, where the value of const parameter `N` is specified | @@ -15,7 +15,7 @@ LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); | +++++++++++++ error[E0271]: type mismatch resolving `FREE<10> == 2` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:38:45 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:37:45 | LL | let (mut arr, mut arr_with_weird_len) = free(); | ^^^^^^ expected `2`, found `10` @@ -24,16 +24,16 @@ LL | let (mut arr, mut arr_with_weird_len) = free(); found constant `10` error[E0284]: type annotations needed for `([(); _], [(); 10])` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:49:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:48:9 | LL | let (mut arr, mut arr_with_weird_len) = proj(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point | = note: cannot satisfy `::PROJ<_> == 10` note: required by a const generic parameter in `proj` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:44:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:43:9 | -LL | fn proj() -> ([(); N], [(); ::PROJ::]) { +LL | fn proj() -> ([(); N], [(); core::direct_const_arg!(::PROJ::)]) { | ^^^^^^^^^^^^^^ required by this const generic parameter in `proj` help: consider giving this pattern a type, where the value of const parameter `N` is specified | @@ -41,7 +41,7 @@ LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); | +++++++++++++ error[E0271]: type mismatch resolving `::PROJ<10> == 2` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:55:45 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:54:45 | LL | let (mut arr, mut arr_with_weird_len) = proj(); | ^^^^^^ expected `2`, found `10` diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr index 11274b947b8f6..4306110c8433d 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr @@ -1,5 +1,5 @@ error: `generic_const_args` requires -Znext-solver=globally to be enabled - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:10:5 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:9:5 | LL | generic_const_args, | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs index ef6d047309b13..8ee278af6ef56 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -6,7 +6,6 @@ #![feature( min_generic_const_args, - macroless_generic_const_args, generic_const_args, //[old]~^ ERROR next-solver generic_const_items @@ -24,7 +23,7 @@ impl Trait for S { const PROJ: usize = 10; } -fn free() -> ([(); N], [(); FREE::]) { +fn free() -> ([(); N], [(); core::direct_const_arg!(FREE::)]) { loop {} } @@ -41,7 +40,7 @@ fn test_free_mismatch() { arr = [(); 10]; } -fn proj() -> ([(); N], [(); ::PROJ::]) { +fn proj() -> ([(); N], [(); core::direct_const_arg!(::PROJ::)]) { loop {} } diff --git a/tests/ui/const-generics/gca/assoc-const.rs b/tests/ui/const-generics/gca/assoc-const.rs new file mode 100644 index 0000000000000..8a8d1b52e7e5a --- /dev/null +++ b/tests/ui/const-generics/gca/assoc-const.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +#![feature(min_generic_const_args, generic_const_args)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for T { + const ASSOC: usize = core::direct_const_arg!(T::RIGID); +} + +trait Other { + const RIGID: usize; +} + +fn foo() { + let a: [(); core::direct_const_arg!(::ASSOC)] = + [(); core::direct_const_arg!(T::RIGID)]; +} + +fn main() {} diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.rs b/tests/ui/const-generics/gca/non-type-equality-fail.rs index 6e71125a4cffb..e058648e3da54 100644 --- a/tests/ui/const-generics/gca/non-type-equality-fail.rs +++ b/tests/ui/const-generics/gca/non-type-equality-fail.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver -#![feature(min_generic_const_args, macroless_generic_const_args, generic_const_args)] +#![feature(min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] trait Trait { @@ -27,13 +27,14 @@ const FREE_B: usize = 1; struct Struct; fn f() { - let _: Struct<{ as Trait>::PROJECTED_A }> = - Struct::<{ as Trait>::PROJECTED_B }>; + let _: Struct<{ core::direct_const_arg!( as Trait>::PROJECTED_A) }> = + Struct::<{ core::direct_const_arg!( as Trait>::PROJECTED_B) }>; //~^ ERROR mismatched types } fn g() { - let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + let _: Struct<{ core::direct_const_arg!(T::PROJECTED_A) }> = + Struct::<{ core::direct_const_arg!(T::PROJECTED_B) }>; //~^ ERROR mismatched types } diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.stderr b/tests/ui/const-generics/gca/non-type-equality-fail.stderr index 5a9c1bb6d4faa..28557d76d84e5 100644 --- a/tests/ui/const-generics/gca/non-type-equality-fail.stderr +++ b/tests/ui/const-generics/gca/non-type-equality-fail.stderr @@ -1,21 +1,21 @@ error[E0308]: mismatched types --> $DIR/non-type-equality-fail.rs:31:9 | -LL | let _: Struct<{ as Trait>::PROJECTED_A }> = - | -------------------------------------------------------- expected due to this -LL | Struct::<{ as Trait>::PROJECTED_B }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected ` as Trait>::PROJECTED_A`, found ` as Trait>::PROJECTED_B` +LL | let _: Struct<{ core::direct_const_arg!( as Trait>::PROJECTED_A) }> = + | --------------------------------------------------------------------------------- expected due to this +LL | Struct::<{ core::direct_const_arg!( as Trait>::PROJECTED_B) }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected ` as Trait>::PROJECTED_A`, found ` as Trait>::PROJECTED_B` | = note: expected struct `Struct< as Trait>::PROJECTED_A>` found struct `Struct< as Trait>::PROJECTED_B>` error[E0308]: mismatched types - --> $DIR/non-type-equality-fail.rs:36:41 + --> $DIR/non-type-equality-fail.rs:37:9 | -LL | let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; - | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `::PROJECTED_A`, found `::PROJECTED_B` - | | - | expected due to this +LL | let _: Struct<{ core::direct_const_arg!(T::PROJECTED_A) }> = + | --------------------------------------------------- expected due to this +LL | Struct::<{ core::direct_const_arg!(T::PROJECTED_B) }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `::PROJECTED_A`, found `::PROJECTED_B` | = note: expected struct `Struct<::PROJECTED_A>` found struct `Struct<::PROJECTED_B>` diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs index e476b5d8124ca..45dcef1f2dc00 100644 --- a/tests/ui/const-generics/gca/non-type-equality-ok.rs +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -35,6 +35,8 @@ struct Struct; fn f() { let _: Struct<{ as Trait>::PROJECTED_A }> = Struct::<{ as Trait>::PROJECTED_A }>; + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; } fn g() { diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr index 0766847a93b18..5a9dd515868b9 100644 --- a/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr +++ b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr @@ -1,5 +1,5 @@ error: `generic_const_args` requires -Znext-solver=globally to be enabled - --> $DIR/wf-inherentimpl.rs:7:12 + --> $DIR/wf-inherentimpl.rs:6:12 | LL | #![feature(generic_const_args, min_generic_const_args)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.rs b/tests/ui/const-generics/gca/wf-inherentimpl.rs index cb3df20daa2dc..c0a7e7f930877 100644 --- a/tests/ui/const-generics/gca/wf-inherentimpl.rs +++ b/tests/ui/const-generics/gca/wf-inherentimpl.rs @@ -3,13 +3,12 @@ //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) #![feature(inherent_associated_types)] -#![feature(macroless_generic_const_args)] #![feature(generic_const_args, min_generic_const_args)] //[old]~^ ERROR `generic_const_args` requires -Znext-solver=globally to be enabled struct Foo; impl Foo { const SIZE: usize = { todo!() }; - fn to_bytes() -> [u8; Self::SIZE] { + fn to_bytes() -> [u8; core::direct_const_arg!(Self::SIZE)] { todo!() } } From 380e55202f43a7358f8f2fd1be6a79615e7e4f93 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 4 Sep 2026 16:58:05 +1000 Subject: [PATCH 26/40] Extract most of `tool_doc!` into non-macro code --- src/bootstrap/src/core/build_steps/doc.rs | 205 ++++++++++++---------- 1 file changed, 115 insertions(+), 90 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 4ae56503a114e..360e1cf88b37c 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1181,10 +1181,11 @@ struct DocArtifacts { impl DocArtifacts { /// Ensure that all passed crates were documented. - fn sanity_check_crates(&self, builder: &Builder<'_>, crates: impl Iterator) - where - S: AsRef, - { + fn sanity_check_crates( + &self, + builder: &Builder<'_>, + crates: impl IntoIterator>, + ) { if builder.config.dry_run() { return; } @@ -1313,41 +1314,27 @@ macro_rules! tool_doc { $path: literal, mode = $mode:expr $(, is_library = $is_library:expr )? - $(, crates = $crates:expr )? + , crates = $crates:expr // Subset of nightly features that are allowed to be used when documenting $(, allow_features: $allow_features:expr )? + $(,)? ) => { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $tool { build_compiler: Compiler, - mode: Mode, target: TargetSelection, } impl $tool { + const PATH: &str = $path; + const MODE: Mode = $mode; + const IS_LIBRARY: bool = false $( || $is_library )?; + const CRATES: &[&str] = &$crates; + const ALLOW_FEATURES: Option<&str> = [$( $allow_features )?].first().copied(); + fn new(builder: &Builder<'_>, target: TargetSelection) -> $tool { - let build_compiler = match $mode { - Mode::ToolRustcPrivate => { - // Rustdoc needs the rustc sysroot available to build. - let compilers = RustcPrivateCompilers::new(builder, builder.top_stage, target); - - // Build rustc docs so that we generate relative links. - builder.ensure(Rustc::from_build_compiler(builder, compilers.build_compiler(), target)); - compilers.build_compiler() - } - Mode::ToolTarget => { - // when shipping multiple docs together in one folder, - // they all need to use the same rustdoc version - prepare_doc_compiler(builder, builder.host_target, builder.top_stage) - } - _ => { - panic!("Unexpected tool mode for documenting: {:?}", $mode); - } - }; - $tool { build_compiler, mode: $mode, target } - } - fn crates() -> &'static [&'static str] { - &$($crates)?[..] + let build_compiler = compiler_for_tool_doc(builder, $tool::MODE, target); + $tool { build_compiler, target } } } @@ -1356,7 +1343,7 @@ macro_rules! tool_doc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path($path) + run.path($tool::PATH) } fn is_default_step(builder: &Builder<'_>) -> bool { @@ -1371,78 +1358,116 @@ macro_rules! tool_doc { /// /// This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder<'_>) -> Self::Output { - let mut source_type = SourceType::InTree; - - if let Some(submodule_path) = submodule_path_of(&builder, $path) { - source_type = SourceType::Submodule; - builder.require_submodule(&submodule_path, None); - } - - let $tool { build_compiler, mode, target } = self; - - // Build cargo command. - let mut cargo = prepare_tool_cargo( + let $tool { build_compiler, target } = self; + document_tool( builder, build_compiler, - mode, + $tool::MODE, target, - Kind::Doc, - $path, - source_type, - &[], - ); - let allow_features = { - let mut _value = ""; - $( _value = $allow_features; )? - _value - }; - - if !allow_features.is_empty() { - cargo.allow_features(allow_features); - } + $tool::PATH, + $tool::IS_LIBRARY, + $tool::CRATES, + $tool::ALLOW_FEATURES, + ) + } - // Only include compiler crates, no dependencies of those, such as `libc`. - cargo.arg("--no-deps"); + fn metadata(&self) -> Option { + Some(StepMetadata::doc(stringify!($tool), self.target).built_by(self.build_compiler)) + } + } + } +} - if false $(|| $is_library)? { - cargo.arg("--lib"); - } +fn compiler_for_tool_doc(builder: &Builder<'_>, mode: Mode, target: TargetSelection) -> Compiler { + match mode { + Mode::ToolRustcPrivate => { + // Rustdoc needs the rustc sysroot available to build. + let compilers = RustcPrivateCompilers::new(builder, builder.top_stage, target); - for krate in $tool::crates() { - cargo.arg("-p").arg(krate); - } + // Build rustc docs so that we generate relative links. + builder.ensure(Rustc::from_build_compiler(builder, compilers.build_compiler(), target)); + compilers.build_compiler() + } + Mode::ToolTarget => { + // when shipping multiple docs together in one folder, + // they all need to use the same rustdoc version + prepare_doc_compiler(builder, builder.host_target, builder.top_stage) + } + _ => panic!("Unexpected tool mode for documenting: {mode:?}"), + } +} - cargo.rustdocflag("--document-private-items"); - // Since we always pass --document-private-items, there's no need to warn about linking to private items. - cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); - cargo.rustdocflag("--enable-index-page"); - cargo.rustdocflag("--show-type-layout"); - cargo.rustdocflag("--generate-link-to-definition"); - - let cargo_target_dir = builder.stage_out(build_compiler, mode); - let target_doc_dir = cargo_target_dir.join(target).join("doc"); - let host_doc_dir = cargo_target_dir.join("doc"); - for krate in $tool::crates() { - let dir_name = normalize_doc_crate_name(krate); - t!(fs::create_dir_all(target_doc_dir.join(&*dir_name))); - } +/// Inner implementation of [`CommandLineStep::run`] for the [`tool_doc`] macro. +#[expect(clippy::too_many_arguments)] +fn document_tool( + builder: &Builder<'_>, + build_compiler: Compiler, + mode: Mode, + target: TargetSelection, + path: &str, + is_library: bool, + crates: &[&str], + allow_features: Option<&str>, +) -> BuiltDocs { + let mut source_type = SourceType::InTree; - let _guard = builder.msg(Kind::Doc, stringify!($tool).to_lowercase(), None, build_compiler, target); - let artifacts = create_docs_and_gather_artifacts(builder, cargo); - artifacts.sanity_check_crates(builder, $tool::crates().iter()); + if let Some(submodule_path) = submodule_path_of(builder, path) { + source_type = SourceType::Submodule; + builder.require_submodule(&submodule_path, None); + } - if !builder.config.dry_run() { - merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir); - merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir); - } - BuiltDocs { out_dir: target_doc_dir, artifacts } - } + // Build cargo command. + let mut cargo = prepare_tool_cargo( + builder, + build_compiler, + mode, + target, + Kind::Doc, + path, + source_type, + &[], + ); - fn metadata(&self) -> Option { - Some(StepMetadata::doc(stringify!($tool), self.target).built_by(self.build_compiler)) - } - } + if let Some(allow_features) = allow_features { + cargo.allow_features(allow_features); + } + + // Only include compiler crates, no dependencies of those, such as `libc`. + cargo.arg("--no-deps"); + + if is_library { + cargo.arg("--lib"); + } + + for krate in crates { + cargo.arg("-p").arg(krate); + } + + cargo.rustdocflag("--document-private-items"); + // Since we always pass --document-private-items, there's no need to warn about linking to private items. + cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); + cargo.rustdocflag("--enable-index-page"); + cargo.rustdocflag("--show-type-layout"); + cargo.rustdocflag("--generate-link-to-definition"); + + let cargo_target_dir = builder.stage_out(build_compiler, mode); + let target_doc_dir = cargo_target_dir.join(target).join("doc"); + let host_doc_dir = cargo_target_dir.join("doc"); + for krate in crates { + let dir_name = normalize_doc_crate_name(krate); + t!(fs::create_dir_all(target_doc_dir.join(&*dir_name))); + } + + let tool_name = Path::new(path).file_name().unwrap().display(); + let _guard = builder.msg(Kind::Doc, tool_name, None, build_compiler, target); + let artifacts = create_docs_and_gather_artifacts(builder, cargo); + artifacts.sanity_check_crates(builder, crates); + + if !builder.config.dry_run() { + merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir); + merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir); } + BuiltDocs { out_dir: target_doc_dir, artifacts } } // NOTE: make sure to register these in `Builder::get_step_description`. From 8f1843dc0a2e0730350dab49f9c09c9295fb758f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 28 Aug 2026 13:25:35 +1000 Subject: [PATCH 27/40] Include feature-gated items in bootstrap tool docs This sets `--all-features` when documenting bootstrap tool crates, and enables rustdoc's `#![feature(doc_cfg)]` to display which items are feature-gated. --- src/bootstrap/src/core/build_steps/doc.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 360e1cf88b37c..d7f580f3ca296 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1443,6 +1443,11 @@ fn document_tool( cargo.arg("-p").arg(krate); } + // Tell rustdoc to document which items require feature flags. + cargo.arg("--all-features"); + cargo.allow_features("doc_cfg"); + cargo.rustdocflag("-Zcrate-attr=feature(doc_cfg)"); + cargo.rustdocflag("--document-private-items"); // Since we always pass --document-private-items, there's no need to warn about linking to private items. cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); From 2a2b4c654eba2e126688bd440396d648e2ca6380 Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 11:27:48 +0200 Subject: [PATCH 28/40] box: fixup map/try_map deallocate calls --- library/alloc/src/boxed.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 473f01660bdb4..4d61bb0fda5f5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -731,12 +731,16 @@ impl Box { let (value, allocation) = Box::take(this); let (raw, alloc) = Box::into_non_null_with_allocator(allocation); if size_of::() == size_of::() && align_of::() == align_of::() { - // ignore-tidy-undocumented-unsafe + // SAFETY: We checked that the memory requirements are the same for both types + // and `raw` is already a valid pointer for the requisite memory. let allocation = unsafe { Box::from_non_null_in(raw.cast::>(), alloc) }; Box::write(allocation, f(value)) } else { - // ignore-tidy-undocumented-unsafe - unsafe { alloc.deallocate(raw.cast(), Layout::for_value(&value)) } + if size_of::() != 0 { + // SAFETY: `raw` isn't dangling since it points to a non-zero-sized + // allocation and is never used again after this point. + unsafe { alloc.deallocate(raw.cast(), Layout::for_value(&value)) } + } Box::new_in(f(value), alloc) } } @@ -773,12 +777,16 @@ impl Box { let (raw, alloc) = Box::into_non_null_with_allocator(allocation); if size_of::() == size_of::() && align_of::() == align_of::() { let allocation = - // ignore-tidy-undocumented-unsafe + // SAFETY: We checked that the memory requirements are the same for both types + // and `raw` is already a valid pointer for the requisite memory. unsafe { Box::from_non_null_in(raw.cast::>(), alloc) }; try { Box::write(allocation, f(value)?) } } else { - // ignore-tidy-undocumented-unsafe - unsafe { alloc.deallocate(raw.cast(), Layout::for_value(&value)) } + if size_of::() != 0 { + // SAFETY: `raw` isn't dangling since it points to a non-zero-sized + // allocation and is never used again after this point. + unsafe { alloc.deallocate(raw.cast(), Layout::for_value(&value)) } + } try { Box::new_in(f(value)?, alloc) } } } From 8f1e14781d4b565619eae679aa68676c66c6b29f Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 11:57:26 +0200 Subject: [PATCH 29/40] string: don't unwind prematurely --- library/alloc/src/lib.rs | 1 + library/alloc/src/string.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 89b15a169dce0..a016285112bab 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -90,6 +90,7 @@ // // Library features: // tidy-alphabetical-start +#![feature(abort_immediate)] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(ascii_char)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4a9750c784fdb..f7613bc042a42 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2119,6 +2119,8 @@ impl String { where R: RangeBounds, { + use core::mem::DropGuard; + // We avoid #81138 (nondeterministic RangeBounds impls) because we only use `range` once, here. let checked_range = slice::range(range, ..self.len()); @@ -2131,8 +2133,12 @@ impl String { "end of range should be a character boundary" ); - // ignore-tidy-undocumented-unsafe + let guard = DropGuard::new((), |_| core::process::abort_immediate()); + // SAFETY: We ensure that we're not replacing across a char boundary and + // that the new contents are valid UTF-8. We also protect against unwinds + // which may leave the string in an invalid state. unsafe { self.as_mut_vec() }.splice(checked_range, replace_with.bytes()); + DropGuard::dismiss(guard); } /// Replaces the leftmost occurrence of a pattern with another string, in-place. From 309c47ac1421b2165862aa32d4e453b927195755 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 10 Aug 2026 10:32:51 +0100 Subject: [PATCH 30/40] Implementation change for removing RegionExt --- .../src/ty/context/impl_interner.rs | 17 +- compiler/rustc_middle/src/ty/generics.rs | 8 +- compiler/rustc_middle/src/ty/region.rs | 158 +++--------------- compiler/rustc_middle/src/ty/sty.rs | 12 +- compiler/rustc_type_ir/src/binder.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 20 ++- compiler/rustc_type_ir/src/interner.rs | 7 +- compiler/rustc_type_ir/src/sty/mod.rs | 92 ++++++++++ 8 files changed, 170 insertions(+), 146 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 74327278dbca6..2522801e2f198 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -12,8 +12,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::CanonicalInputData; use rustc_type_ir::{ - BoundVar, CollectAndApply, DebruijnIndex, Interner, TypeFoldable, Unnormalized, VisitorResult, - search_graph, try_visit, + BoundVar, CollectAndApply, DebruijnIndex, Interner, RegionVid, TypeFoldable, Unnormalized, + VisitorResult, search_graph, try_visit, }; use crate::dep_graph::{DepKind, DepNodeIndex}; @@ -650,6 +650,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) } + fn span_delayed_bug(self, span: Self::Span, msg: impl ToString) -> ErrorGuaranteed { + self.dcx().span_delayed_bug(span, msg.to_string()) + } + fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool { self.is_general_coroutine(coroutine_def_id) } @@ -733,6 +737,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.lifetimes.re_static } + fn intern_re_var(self, rv: RegionVid) -> Region<'tcx> { + // Use a pre-interned one when possible. + self.lifetimes + .re_vars + .get(rv.as_usize()) + .copied() + .unwrap_or_else(|| self.intern_region(ty::ReVar(rv))) + } + fn intern_region(self, region_kind: RegionKind<'tcx>) -> Region<'tcx> { self.intern_region(region_kind) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index bfdb89dc409f6..55dd1c3067423 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -9,7 +9,6 @@ use rustc_type_ir::{TypeSuperVisitable as _, TypeVisitable, TypeVisitor}; use tracing::instrument; use super::{Clause, InstantiatedClauses, ParamConst, ParamTy, Ty, TyCtxt, Unnormalized}; -use crate::ty::region::RegionExt; use crate::ty::{self, ClauseKind, EarlyBinder, GenericArgsRef, Region, RegionKind, TyKind}; #[derive(Clone, Debug, TyEncodable, TyDecodable, StableHash)] @@ -152,6 +151,13 @@ impl<'tcx> rustc_type_ir::inherent::GenericsOf> for &'tcx Generics fn count(&self) -> usize { self.parent_count + self.own_params.len() } + fn generics_of_early_param_region_def_id( + tcx: TyCtxt<'tcx>, + def_id: DefId, + epr: ty::EarlyParamRegion, + ) -> DefId { + tcx.generics_of(def_id).region_param(epr, tcx).def_id + } } impl<'tcx> Generics { diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 154873c435e1c..928fdead34c90 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -1,7 +1,6 @@ -use rustc_errors::MultiSpan; use rustc_hir::def_id::DefId; -use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Symbol, kw, sym}; +use rustc_macros::{StableHash, TyDecodable, TyEncodable}; +use rustc_span::{Symbol, kw}; pub use rustc_type_ir::RegionVid; use rustc_type_ir::{ LateParamRegion as IrLateParamRegion, Region as IrRegion, RegionKind as IrRegionKind, @@ -13,139 +12,6 @@ pub type Region<'tcx> = IrRegion>; pub type RegionKind<'tcx> = IrRegionKind>; pub type LateParamRegion<'tcx> = IrLateParamRegion>; -#[extension(pub trait RegionExt<'tcx>)] -impl<'tcx> Region<'tcx> { - #[inline] - fn new_early_param( - tcx: TyCtxt<'tcx>, - early_bound_region: ty::EarlyParamRegion, - ) -> Region<'tcx> { - tcx.intern_region(ty::ReEarlyParam(early_bound_region)) - } - - #[inline] - fn new_late_param(tcx: TyCtxt<'tcx>, scope: DefId, kind: LateParamRegionKind) -> Region<'tcx> { - let data = LateParamRegion { scope, kind }; - tcx.intern_region(ty::ReLateParam(data)) - } - - #[inline] - fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { - // Use a pre-interned one when possible. - tcx.lifetimes - .re_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) - } - - /// Constructs a `RegionKind::ReError` region. - #[track_caller] - fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Region<'tcx> { - tcx.intern_region(ty::ReError(guar)) - } - - /// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets - /// used. - #[track_caller] - fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { - Region::new_error_with_message( - tcx, - DUMMY_SP, - "RegionKind::ReError constructed but no error reported", - ) - } - - /// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg` - /// to ensure it gets used. - #[track_caller] - fn new_error_with_message>( - tcx: TyCtxt<'tcx>, - span: S, - msg: &'static str, - ) -> Region<'tcx> { - let reported = tcx.dcx().span_delayed_bug(span, msg); - Region::new_error(tcx, reported) - } - - /// Avoid this in favour of more specific `new_*` methods, where possible, - /// to avoid the cost of the `match`. - fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { - match kind { - ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), - ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), region) => { - Region::new_bound(tcx, debruijn, region) - } - ty::ReBound(ty::BoundVarIndexKind::Canonical, region) => { - Region::new_canonical_bound(tcx, region.var) - } - ty::ReLateParam(ty::LateParamRegion { scope, kind }) => { - Region::new_late_param(tcx, scope, kind) - } - ty::ReStatic => tcx.lifetimes.re_static, - ty::ReVar(vid) => Region::new_var(tcx, vid), - ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), - ty::ReErased => tcx.lifetimes.re_erased, - ty::ReError(reported) => Region::new_error(tcx, reported), - } - } - - fn get_name(self, tcx: TyCtxt<'tcx>) -> Option { - match self.kind() { - ty::ReEarlyParam(ebr) => ebr.is_named().then_some(ebr.name), - ty::ReBound(_, br) => br.kind.get_name(tcx), - ty::ReLateParam(fr) => fr.kind.get_name(tcx), - ty::ReStatic => Some(kw::StaticLifetime), - ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(tcx), - _ => None, - } - } - - fn get_name_or_anon(self, tcx: TyCtxt<'tcx>) -> Symbol { - match self.get_name(tcx) { - Some(name) => name, - None => sym::anon, - } - } - - /// Is this region named by the user? - fn is_named(self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind() { - ty::ReEarlyParam(ebr) => ebr.is_named(), - ty::ReBound(_, br) => br.kind.is_named(tcx), - ty::ReLateParam(fr) => fr.kind.is_named(tcx), - ty::ReStatic => true, - ty::ReVar(..) => false, - ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(tcx), - ty::ReErased => false, - ty::ReError(_) => false, - } - } - - #[inline] - fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { - match self.kind() { - ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index, - _ => false, - } - } - - /// Given some item `binding_item`, check if this region is a generic parameter introduced by it - /// or one of the parent generics. Returns the `DefId` of the parameter definition if so. - fn opt_param_def_id(self, tcx: TyCtxt<'tcx>, binding_item: DefId) -> Option { - match self.kind() { - ty::ReEarlyParam(ebr) => { - Some(tcx.generics_of(binding_item).region_param(ebr, tcx).def_id) - } - ty::ReLateParam(ty::LateParamRegion { - kind: ty::LateParamRegionKind::Named(def_id), - .. - }) => Some(def_id), - _ => None, - } - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(StableHash)] pub struct EarlyParamRegion { @@ -154,6 +20,12 @@ pub struct EarlyParamRegion { } impl EarlyParamRegion { + #[inline] + pub fn get_name(&self) -> Option { + if self.is_named() { Some(self.name) } else { None } + } + + #[inline] /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn is_named(&self) -> bool { @@ -167,6 +39,20 @@ impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion { } } +impl<'tcx> rustc_type_ir::inherent::RegionName> for EarlyParamRegion { + #[inline] + fn get_name(&self, _tcx: TyCtxt<'tcx>) -> Option { + self.get_name() + } + + #[inline] + /// Does this early bound region have a name? Early bound regions normally + /// always have names except when using anonymous lifetimes (`'_`). + fn is_named(&self, _tcx: TyCtxt<'tcx>) -> bool { + self.is_named() + } +} + impl std::fmt::Debug for EarlyParamRegion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}/#{}", self.name, self.index) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 013064b5cec4b..3da215e61acf5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2196,8 +2196,16 @@ impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List rustc_type_ir::inherent::Symbol> for Symbol { - fn is_kw_underscore_lifetime(self) -> bool { - self == kw::UnderscoreLifetime + fn get_kw_underscore_lifetime() -> Self { + kw::UnderscoreLifetime + } + + fn get_kw_static_lifetime() -> Self { + kw::StaticLifetime + } + + fn get_sym_anon() -> Self { + sym::anon } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index db867364b3585..5a9d9a48717df 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -1028,7 +1028,7 @@ impl BoundRegionKind { match *self { ty::BoundRegionKind::Named(def_id) => { let name = tcx.item_name(def_id); - if name.is_kw_underscore_lifetime() { None } else { Some(name) } + if name == I::Symbol::get_kw_underscore_lifetime() { None } else { Some(name) } } ty::BoundRegionKind::NamedForPrinting(name) => Some(name), _ => None, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b08cf4c5876a9..5a8237229cf2e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -286,6 +286,11 @@ pub trait ExprConst>: Copy + Debug + Hash + Eq + R #[rust_analyzer::prefer_underscore_import] pub trait GenericsOf> { fn count(&self) -> usize; + fn generics_of_early_param_region_def_id( + interner: I, + def_id: I::DefId, + ebr: I::EarlyParamRegion, + ) -> I::DefId; } #[rust_analyzer::prefer_underscore_import] @@ -768,6 +773,17 @@ impl<'a, S: SliceLike> SliceLike for &'a S { } #[rust_analyzer::prefer_underscore_import] -pub trait Symbol: Copy + Hash + PartialEq + Eq + Debug { - fn is_kw_underscore_lifetime(self) -> bool; +pub trait Symbol: Copy + Hash + PartialEq + Eq + Debug { + fn get_kw_underscore_lifetime() -> I::Symbol; + fn get_kw_static_lifetime() -> I::Symbol; + fn get_sym_anon() -> I::Symbol; +} + +pub trait RegionName: Copy + Hash + PartialEq + Eq + Debug { + fn get_name(&self, interner: I) -> Option; + fn is_named(&self, interner: I) -> bool; +} + +pub trait DefIdGetter: Copy + Hash + PartialEq + Eq + Debug { + fn get_def_id(self) -> Option; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1dfb34d94c0fc..0530b71b37207 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -21,8 +21,8 @@ use crate::solve::{ }; use crate::visit::{Flags, TypeVisitable}; use crate::{ - self as ty, AliasTermKind, BoundRegion, BoundVar, CanonicalParamEnvCache, DebruijnIndex, - Region, RegionKind, TraitRef, search_graph, + self as ty, self as ty, AliasTermKind, BoundRegion, BoundVar, CanonicalParamEnvCache, + DebruijnIndex, Region, RegionKind, RegionVid, TraitRef, search_graph, }; /// The central trait in the shared abstraction layer, specifying all implementation-specific @@ -491,6 +491,7 @@ pub trait Interner: fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool; fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; + fn span_delayed_bug(self, span: Self::Span, msg: impl ToString) -> Self::ErrorGuaranteed; fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool; fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool; @@ -528,6 +529,8 @@ pub trait Interner: fn get_re_static_lifetime(self) -> Region; + fn intern_re_var(self, rv: RegionVid) -> Region; + fn intern_region(self, region_kind: RegionKind) -> Region; fn intern_bound_region( diff --git a/compiler/rustc_type_ir/src/sty/mod.rs b/compiler/rustc_type_ir/src/sty/mod.rs index e82d062a155a6..a4e8c32b3d2f0 100644 --- a/compiler/rustc_type_ir/src/sty/mod.rs +++ b/compiler/rustc_type_ir/src/sty/mod.rs @@ -24,6 +24,90 @@ pub struct Region(pub I::InternedRegionKind); // These are only the `inherent` trait methods that have been ported across impl Region { + #[inline] + pub fn new_var(interner: I, v: RegionVid) -> Self { + interner.intern_re_var(v) + } + + pub fn get_name(self, interner: I) -> Option { + match self.kind() { + RegionKind::ReEarlyParam(ebr) => ebr.get_name(interner), + RegionKind::ReBound(_, br) => br.kind.get_name(interner), + RegionKind::ReLateParam(fr) => fr.get_name(interner), + RegionKind::ReStatic => Some(I::Symbol::get_kw_static_lifetime()), + RegionKind::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(interner), + _ => None, + } + } + + pub fn get_name_or_anon(self, interner: I) -> I::Symbol { + match self.get_name(interner) { + Some(name) => name, + None => I::Symbol::get_sym_anon(), + } + } + + /// Given some item `binding_item`, check if this region is a generic parameter introduced by it + /// or one of the parent generics. Returns the `DefId` of the parameter definition if so. + pub fn opt_param_def_id(self, interner: I, binding_item: I::DefId) -> Option { + match self.kind() { + RegionKind::ReEarlyParam(ebr) => Some( + I::GenericsOf::generics_of_early_param_region_def_id(interner, binding_item, ebr), + ), + RegionKind::ReLateParam(param) => param.get_def_id(), + _ => None, + } + } + + /// Is this region named by the user? + pub fn is_named(self, interner: I) -> bool { + match self.kind() { + RegionKind::ReEarlyParam(ebr) => ebr.is_named(interner), + RegionKind::ReBound(_, br) => br.kind.is_named(interner), + RegionKind::ReLateParam(fr) => fr.is_named(interner), + RegionKind::ReStatic => true, + RegionKind::ReVar(..) => false, + RegionKind::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(interner), + RegionKind::ReErased => false, + RegionKind::ReError(_) => false, + } + } + + /// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets + /// used. + #[track_caller] + pub fn new_error_misc(interner: I) -> Self { + Self::new_error_with_message( + interner, + I::Span::dummy(), + "RegionKind::ReError constructed but no error reported", + ) + } + + /// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg` + /// to ensure it gets used. + #[track_caller] + pub fn new_error_with_message(interner: I, span: I::Span, msg: impl ToString) -> Self { + let reported = interner.span_delayed_bug(span, msg); + Self::new_error(interner, reported) + } + + #[inline] + pub fn new_late_param(interner: I, late_param_region: I::LateParamRegion) -> Self { + interner.intern_region(RegionKind::ReLateParam(late_param_region)) + } + + #[inline] + pub fn new_early_param(interner: I, early_bound_region: I::EarlyParamRegion) -> Self { + interner.intern_region(RegionKind::ReEarlyParam(early_bound_region)) + } + + /// Constructs a `RegionKind::ReError` region. + #[track_caller] + pub fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self { + interner.intern_region(RegionKind::ReError(guar)) + } + #[inline] pub fn new_bound(interner: I, debruijn: DebruijnIndex, bound_region: BoundRegion) -> Self { interner.intern_bound_region(debruijn, bound_region) @@ -159,6 +243,14 @@ impl Region { pub fn kind(self) -> RegionKind { self.0.get() } + + #[inline] + pub fn bound_at_or_above_binder(self, index: DebruijnIndex) -> bool { + match self.kind() { + RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index, + _ => false, + } + } } impl Flags for Region { From f3cf30d76b9dff7fb2802c4f77296a1f91e0dae5 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 10 Aug 2026 10:33:09 +0100 Subject: [PATCH 31/40] update imports and method signature changes --- .../src/diagnostics/bound_region_errors.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 3 +-- compiler/rustc_borrowck/src/nll.rs | 2 +- compiler/rustc_borrowck/src/polonius/dump.rs | 2 +- .../src/region_infer/graphviz.rs | 2 +- .../rustc_borrowck/src/region_infer/mod.rs | 4 +-- .../src/region_infer/opaque_types/mod.rs | 2 +- .../src/type_check/constraint_conversion.rs | 3 +-- .../rustc_borrowck/src/universal_regions.rs | 2 +- .../src/check/always_applicable.rs | 2 +- .../src/check/compare_impl_item.rs | 6 ++--- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 6 ++--- compiler/rustc_hir_analysis/src/collect.rs | 4 +-- .../src/collect/clauses_of.rs | 3 +-- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_analysis/src/delegation.rs | 3 +-- .../src/hir_ty_lowering/mod.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 4 +-- compiler/rustc_infer/src/infer/mod.rs | 4 +-- .../src/infer/outlives/obligations.rs | 4 +-- .../src/infer/region_constraints/mod.rs | 2 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 1 - compiler/rustc_middle/src/ty/fold.rs | 1 - compiler/rustc_middle/src/ty/generics.rs | 8 ++---- compiler/rustc_middle/src/ty/mod.rs | 3 +-- compiler/rustc_middle/src/ty/opaque_types.rs | 3 +-- compiler/rustc_middle/src/ty/print/pretty.rs | 1 - compiler/rustc_middle/src/ty/region.rs | 18 +++++++++++++ compiler/rustc_middle/src/ty/sty.rs | 14 +++-------- .../nice_region_error/named_anon_conflict.rs | 1 - .../nice_region_error/placeholder_error.rs | 4 +-- .../nice_region_error/static_impl_trait.rs | 2 +- .../trait_impl_difference.rs | 2 +- .../src/error_reporting/infer/region.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 4 +-- compiler/rustc_type_ir/src/binder.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 12 +++------ compiler/rustc_type_ir/src/interner.rs | 25 +++++++++++++++---- compiler/rustc_type_ir/src/sty/mod.rs | 20 +++++++-------- src/librustdoc/clean/mod.rs | 3 +-- 45 files changed, 100 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index a8338c9e3c41f..8c9c444bd1793 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -14,7 +14,7 @@ use rustc_infer::traits::query::{ }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ - self, RePlaceholder, Region, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, + self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c22698003f7ee..97931fc76f152 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, PredicateKind, RegionExt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, + self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, suggest_constraining_type_params, }; use rustc_mir_dataflow::move_paths::{Init, InitKind, InitLocation, MoveOutIndex, MovePathIndex}; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b43694596d17c..a972b37cd42d2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -15,8 +15,7 @@ use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{ - self, GenericArgs, Region, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, - fold_regions, + self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions, }; use rustc_span::{Ident, Span, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 5a1358b9a311e..1a328f62fc73e 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -12,7 +12,7 @@ use rustc_index::IndexSlice; use rustc_middle::mir::pretty::PrettyPrintMirOptions; use rustc_middle::mir::{Body, MirDumper, PassWhere, Promoted}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, RegionExt, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_session::config::MirIncludeSpans; diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 2b3d8b4fdac22..5285f724b02ec 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_index::IndexVec; use rustc_middle::mir::pretty::{MirDumper, PassWhere, PrettyPrintMirOptions}; use rustc_middle::mir::{Body, Location}; -use rustc_middle::ty::{RegionExt, RegionVid, TyCtxt}; +use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; use rustc_session::config::MirIncludeSpans; diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 6583bc24e2015..ceb33d82deba8 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -7,7 +7,7 @@ use std::io::{self, Write}; use itertools::Itertools; use rustc_graphviz as dot; -use rustc_middle::ty::{RegionExt, UniverseIndex}; +use rustc_middle::ty::UniverseIndex; use super::*; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d3fc7152acc44..534cd1327bbe5 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -17,9 +17,7 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{ - self, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions, -}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::hygiene::DesugaringKind; use rustc_span::{DUMMY_SP, Span}; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index e347dc2d13dfc..a154078b7ad86 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -11,7 +11,7 @@ use rustc_macros::extension; use rustc_middle::mir::{Body, ConstraintCategory}; use rustc_middle::ty::{ self, DefiningScopeKind, DefinitionSiteHiddenType, FallibleTypeFolder, Flags, GenericArg, - GenericArgsRef, OpaqueTypeKey, ProvisionalHiddenType, Region, RegionExt, RegionVid, Ty, TyCtxt, + GenericArgsRef, OpaqueTypeKey, ProvisionalHiddenType, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt, Unnormalized, fold_regions, }; use rustc_mir_dataflow::points::DenseLocationMap; diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index f845d9137f759..e20f9a646a953 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,8 +6,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_middle::ty::{ - self, GenericArgKind, RegionExt, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, - fold_regions, + self, GenericArgKind, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions, }; use rustc_span::Span; use tracing::{debug, instrument}; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index fbde85ef6aec4..f16c811031b08 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -27,7 +27,7 @@ use rustc_middle::mir::RETURN_PLACE; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, BoundVariableKind, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, - List, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, + List, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, kw, sym}; diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 60636a1164926..ca9874ac727a1 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -11,7 +11,7 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::span_bug; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::{self, GenericArgsRef, RegionExt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e5d26cf72f9a5..ad34f327c3060 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -14,9 +14,9 @@ use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInfer use rustc_infer::traits::{TraitErrors, util}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, RegionExt, Ty, TyCtxt, - TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, - TypingMode, Unnormalized, Upcast, + self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + Unnormalized, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, DUMMY_SP, Span}; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index eac3762ef9af8..9ce935c4389a5 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -89,7 +89,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, OutlivesClause, Region, RegionExt, Ty, TyCtxt, TypingMode, + self, GenericArgs, GenericArgsRef, OutlivesClause, Region, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::diagnostics::feature_err; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4224f8394ea4a..066ed197cde5b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -23,9 +23,9 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::solve::NoSolution; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, GenericArgKind, GenericArgs, GenericParamDefKind, RegionExt, Ty, TyCtxt, TypeFlags, - TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, - Unnormalized, Upcast, + self, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, + Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::diagnostics::feature_err; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 65fd562a4ebf6..7a59ebfe47842 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,8 +34,8 @@ use rustc_lint_defs::builtin::REPR_C_ENUMS_LARGER_THAN_INT; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{ - self, AdtKind, Const, IsSuggestable, RegionExt, Ty, TyCtxt, TypeVisitableExt, TypingMode, - Unnormalized, fold_regions, + self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, + fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index 488b9a09e6106..c12c4a199b250 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -7,8 +7,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::find_attr; use rustc_middle::ty::{ - self, GenericClauses, ImplTraitInTraitData, RegionExt, Ty, TyCtxt, TypeVisitable, TypeVisitor, - Upcast, + self, GenericClauses, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span}; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index dbd210e08ea50..a3d91e834a3e8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -33,7 +33,7 @@ use tracing::{debug, debug_span, instrument}; use crate::diagnostics; use crate::hir::definitions::PerParentDisambiguatorState; -#[extension(trait RegionExt)] +#[extension(trait ResolvedArgExt)] impl ResolvedArg { fn early(param: &GenericParam<'_>) -> ResolvedArg { ResolvedArg::EarlyBound(param.def_id) diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 5324b4d3552c6..1ae3fecf92096 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -7,8 +7,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{DelegationSelfTyPropagationKind, PathSegment}; use rustc_middle::ty::{ - self, EarlyBinder, RegionExt, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, + self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_span::{ErrorGuaranteed, Span, kw}; 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 cfff8d1768f0e..7f53a91d33d07 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -44,7 +44,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::{ self, Const, FnSigKind, GenericArgKind, GenericArgsRef, GenericParamDefKind, LitToConstInput, - RegionExt, Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, + Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, const_lit_matches_ty, fold_regions, }; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 05062155915d6..e59ca32aba116 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -31,9 +31,7 @@ use rustc_middle::ty::print::{ PrintTraitRefExt as _, with_crate_prefix, with_forced_trimmed_paths, with_no_visible_paths_if_doc_hidden, }; -use rustc_middle::ty::{ - self, GenericArgKind, IsSuggestable, RegionExt, Ty, TyCtxt, TypeVisitableExt, -}; +use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, Span, Symbol, edit_distance, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e193f28f9738d..56fcc72bd9769 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -30,8 +30,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, OpaqueTypeKey, ProvisionalHiddenType, - PseudoCanonicalInput, RegionExt, Term, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, + PseudoCanonicalInput, Term, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, }; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::{CanonicalizerState, MayBeErased}; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a861b89cceb8e..50ba91e82fccc 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -65,8 +65,8 @@ use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ - self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesClause, Region, RegionExt, RegionVid, Ty, - TyCtxt, TypeVisitableExt, eager_resolve_vars, + self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesClause, Region, RegionVid, Ty, TyCtxt, + TypeVisitableExt, eager_resolve_vars, }; use rustc_span::Span; use smallvec::smallvec; diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 7db45fde6c8d7..240b288728832 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -8,7 +8,7 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; use rustc_index::IndexVec; use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionExt, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 257b9e1db8e33..e5845e904229f 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::relate::{ structurally_relate_tys, }; use rustc_middle::ty::{ - self, RegionExt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Unnormalized, }; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5b5656c05f10d..df46910c06e83 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -68,7 +68,6 @@ use crate::traits::solve::{ PredefinedOpaques, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; -use crate::ty::region::RegionExt; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, ClausePolarity, Clauses, Const, FnSigKind, GenericArg, GenericArgs, GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index c146e7c982de9..3d9148d6ed7ba 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -2,7 +2,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_type_ir::data_structures::DelayedMap; -use crate::ty::region::RegionExt; use crate::ty::{ self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 55dd1c3067423..f5e983ab48f92 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -151,12 +151,8 @@ impl<'tcx> rustc_type_ir::inherent::GenericsOf> for &'tcx Generics fn count(&self) -> usize { self.parent_count + self.own_params.len() } - fn generics_of_early_param_region_def_id( - tcx: TyCtxt<'tcx>, - def_id: DefId, - epr: ty::EarlyParamRegion, - ) -> DefId { - tcx.generics_of(def_id).region_param(epr, tcx).def_id + fn param_region_def_id(self, tcx: TyCtxt<'tcx>, ebr: ty::EarlyParamRegion) -> DefId { + self.region_param(ebr, tcx).def_id } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0ced7d1ea2bc5..b53fdc5621736 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -96,8 +96,7 @@ pub use self::predicate::{ TraitRef, TypeOutlivesClause, }; pub use self::region::{ - EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region, RegionExt, RegionKind, - RegionVid, + EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region, RegionKind, RegionVid, }; pub use self::sty::{ Alias, AliasTy, AliasTyKind, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 8d835a3d2153a..bf716e8027a0a 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -5,8 +5,7 @@ use tracing::{debug, instrument, trace}; use crate::diagnostics::ConstNotUsedTraitAlias; use crate::ty::{ - self, GenericArg, GenericArgKind, RegionExt, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, + self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, }; pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f5960e65c4493..07e935e265c8b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -24,7 +24,6 @@ use smallvec::SmallVec; use super::*; use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::query::{IntoQueryKey, Providers}; -use crate::ty::region::RegionExt; use crate::ty::{ ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitClause, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 928fdead34c90..fbb40465cd5fd 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -123,6 +123,24 @@ impl LateParamRegionKind { } } +impl<'tcx> rustc_type_ir::inherent::RegionName> for LateParamRegionKind { + #[inline] + fn get_name(&self, tcx: TyCtxt<'tcx>) -> Option { + self.get_name(tcx) + } + + #[inline] + fn is_named(&self, tcx: TyCtxt<'tcx>) -> bool { + self.is_named(tcx) + } +} + +impl<'tcx> rustc_type_ir::inherent::DefIdGetter> for LateParamRegionKind { + fn get_def_id(self) -> Option { + self.get_id() + } +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3da215e61acf5..b711776520f76 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2196,17 +2196,9 @@ impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List rustc_type_ir::inherent::Symbol> for Symbol { - fn get_kw_underscore_lifetime() -> Self { - kw::UnderscoreLifetime - } - - fn get_kw_static_lifetime() -> Self { - kw::StaticLifetime - } - - fn get_sym_anon() -> Self { - sym::anon - } + const KW_UNDERSCORE_LIFETIME: Self = kw::UnderscoreLifetime; + const KW_STATIC_LIFETIME: Self = kw::StaticLifetime; + const SYM_ANON: Self = sym::anon; } // Some types are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index 41ed83c11bbd5..f555f0435dd8f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -3,7 +3,6 @@ use rustc_errors::Diag; use rustc_middle::ty; -use rustc_middle::ty::RegionExt; use tracing::debug; use crate::diagnostics::ExplicitLifetimeRequired; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index ccbe23cf7a631..7f07fab6e8474 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -8,9 +8,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode}; -use rustc_middle::ty::{ - self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, RegionExt, TyCtxt, -}; +use rustc_middle::ty::{self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, TyCtxt}; use rustc_structures::Limit; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 1d58e8518ba56..2d48b41bcb361 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -8,7 +8,7 @@ use rustc_hir::{ self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; -use rustc_middle::ty::{self, RegionExt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; use rustc_span::{Ident, Span}; use tracing::debug; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 87785c403fa4e..f1be118896b01 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -10,7 +10,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; -use rustc_middle::ty::{self, RegionExt, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::{Ident, Span}; use tracing::debug; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 7f4ca7a572988..73b98b8eda1a6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -13,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{ - self, IsSuggestable, Region, RegionExt, Ty, TyCtxt, TypeVisitableExt as _, Upcast as _, + self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _, Upcast as _, }; use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol, kw, sym}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4593ac035dc95..7357d1738d8c3 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,7 +32,7 @@ use rustc_macros::TypeVisitable; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, BottomUpFolder, Clause, GenericArgs, GenericArgsRef, RegionExt, Ty, TyCtxt, TypeFoldable, + self, BottomUpFolder, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, }; diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 3653b6ee3670d..66ba76bcd6474 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, RegionExt, Ty, TyCtxt, Unnormalized, fold_regions}; +use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized, fold_regions}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index e54e8f098d175..056165d19ae04 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -6,8 +6,8 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, RegionExt, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, - Unnormalized, Upcast, fold_regions, + self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Unnormalized, + Upcast, fold_regions, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 5a9d9a48717df..7fc29cd8ebcf1 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -1028,7 +1028,7 @@ impl BoundRegionKind { match *self { ty::BoundRegionKind::Named(def_id) => { let name = tcx.item_name(def_id); - if name == I::Symbol::get_kw_underscore_lifetime() { None } else { Some(name) } + if name == I::Symbol::KW_UNDERSCORE_LIFETIME { None } else { Some(name) } } ty::BoundRegionKind::NamedForPrinting(name) => Some(name), _ => None, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 5a8237229cf2e..bf90ef707c051 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -286,11 +286,7 @@ pub trait ExprConst>: Copy + Debug + Hash + Eq + R #[rust_analyzer::prefer_underscore_import] pub trait GenericsOf> { fn count(&self) -> usize; - fn generics_of_early_param_region_def_id( - interner: I, - def_id: I::DefId, - ebr: I::EarlyParamRegion, - ) -> I::DefId; + fn param_region_def_id(self, interner: I, ebr: I::EarlyParamRegion) -> I::DefId; } #[rust_analyzer::prefer_underscore_import] @@ -774,9 +770,9 @@ impl<'a, S: SliceLike> SliceLike for &'a S { #[rust_analyzer::prefer_underscore_import] pub trait Symbol: Copy + Hash + PartialEq + Eq + Debug { - fn get_kw_underscore_lifetime() -> I::Symbol; - fn get_kw_static_lifetime() -> I::Symbol; - fn get_sym_anon() -> I::Symbol; + const KW_UNDERSCORE_LIFETIME: Self; + const KW_STATIC_LIFETIME: Self; + const SYM_ANON: Self; } pub trait RegionName: Copy + Hash + PartialEq + Eq + Debug { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0530b71b37207..fe7f66f891e82 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -21,8 +21,8 @@ use crate::solve::{ }; use crate::visit::{Flags, TypeVisitable}; use crate::{ - self as ty, self as ty, AliasTermKind, BoundRegion, BoundVar, CanonicalParamEnvCache, - DebruijnIndex, Region, RegionKind, RegionVid, TraitRef, search_graph, + self as ty, AliasTermKind, BoundRegion, BoundVar, CanonicalParamEnvCache, DebruijnIndex, + Region, RegionKind, RegionVid, TraitRef, search_graph, }; /// The central trait in the shared abstraction layer, specifying all implementation-specific @@ -211,16 +211,31 @@ pub trait Interner: /// Do not uplift, the underlying types differ between r-a and rustc. /// /// See . - type EarlyParamRegion: ParamLike; + type EarlyParamRegion: ParamLike + RegionName; /// (2026/08/13) /// Do not uplift, the underlying types differ between r-a and rustc. /// /// See . #[cfg(feature = "nightly")] - type LateParamRegionKind: Clone + Copy + Debug + PartialEq + Eq + Hash + StableHash; + type LateParamRegionKind: Clone + + Copy + + Debug + + PartialEq + + Eq + + Hash + + StableHash + + DefIdGetter + + RegionName; #[cfg(not(feature = "nightly"))] - type LateParamRegionKind: Clone + Copy + Debug + PartialEq + Eq + Hash; + type LateParamRegionKind: Clone + + Copy + + Debug + + PartialEq + + Eq + + Hash + + DefIdGetter + + RegionName; type InternedRegionKind: Interned>; diff --git a/compiler/rustc_type_ir/src/sty/mod.rs b/compiler/rustc_type_ir/src/sty/mod.rs index a4e8c32b3d2f0..0dfdda6af16cc 100644 --- a/compiler/rustc_type_ir/src/sty/mod.rs +++ b/compiler/rustc_type_ir/src/sty/mod.rs @@ -33,8 +33,8 @@ impl Region { match self.kind() { RegionKind::ReEarlyParam(ebr) => ebr.get_name(interner), RegionKind::ReBound(_, br) => br.kind.get_name(interner), - RegionKind::ReLateParam(fr) => fr.get_name(interner), - RegionKind::ReStatic => Some(I::Symbol::get_kw_static_lifetime()), + RegionKind::ReLateParam(fr) => fr.kind.get_name(interner), + RegionKind::ReStatic => Some(I::Symbol::KW_STATIC_LIFETIME), RegionKind::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(interner), _ => None, } @@ -43,7 +43,7 @@ impl Region { pub fn get_name_or_anon(self, interner: I) -> I::Symbol { match self.get_name(interner) { Some(name) => name, - None => I::Symbol::get_sym_anon(), + None => I::Symbol::SYM_ANON, } } @@ -51,10 +51,10 @@ impl Region { /// or one of the parent generics. Returns the `DefId` of the parameter definition if so. pub fn opt_param_def_id(self, interner: I, binding_item: I::DefId) -> Option { match self.kind() { - RegionKind::ReEarlyParam(ebr) => Some( - I::GenericsOf::generics_of_early_param_region_def_id(interner, binding_item, ebr), - ), - RegionKind::ReLateParam(param) => param.get_def_id(), + RegionKind::ReEarlyParam(ebr) => { + Some(interner.generics_of(binding_item).param_region_def_id(interner, ebr)) + } + RegionKind::ReLateParam(param) => param.kind.get_def_id(), _ => None, } } @@ -64,7 +64,7 @@ impl Region { match self.kind() { RegionKind::ReEarlyParam(ebr) => ebr.is_named(interner), RegionKind::ReBound(_, br) => br.kind.is_named(interner), - RegionKind::ReLateParam(fr) => fr.is_named(interner), + RegionKind::ReLateParam(fr) => fr.kind.is_named(interner), RegionKind::ReStatic => true, RegionKind::ReVar(..) => false, RegionKind::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(interner), @@ -93,8 +93,8 @@ impl Region { } #[inline] - pub fn new_late_param(interner: I, late_param_region: I::LateParamRegion) -> Self { - interner.intern_region(RegionKind::ReLateParam(late_param_region)) + pub fn new_late_param(interner: I, scope: I::DefId, kind: I::LateParamRegionKind) -> Self { + interner.intern_region(RegionKind::ReLateParam(LateParamRegion { scope, kind })) } #[inline] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 784a80ef02cd2..f1b903bf5dd22 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -48,8 +48,7 @@ use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{ - self, AdtKind, GenericArgsRef, RegionExt, Ty, TyCtxt, TypeVisitableExt, TypingMode, - Unnormalized, + self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, }; use rustc_middle::{bug, span_bug}; use rustc_span::ExpnKind; From 2489df9e380abf396573e97b26488dbe13cbd3b1 Mon Sep 17 00:00:00 2001 From: ZephyrCodesStuff <35661622+ZephyrCodesStuff@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:56:45 +0200 Subject: [PATCH 32/40] Add new Tier-3 target: `powerpc64-sony-ps3` --- compiler/rustc_target/src/spec/mod.rs | 2 + .../src/spec/targets/powerpc64_sony_ps3.rs | 107 ++++++++++++++++++ .../crates/symcheck/src/main.rs | 2 + src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../platform-support/powerpc64-sony-ps3.md | 93 +++++++++++++++ src/librustdoc/clean/cfg.rs | 1 + .../src/completions/attribute/cfg.rs | 3 +- tests/assembly-llvm/targets/targets-elf.rs | 3 + tests/rustdoc-html/doc-cfg/all-targets.rs | 11 +- tests/ui/check-cfg/cfg-crate-features.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 4 +- 12 files changed, 221 insertions(+), 9 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs create mode 100644 src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a1c8fd304cd94..0f192379ce7fc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1615,6 +1615,7 @@ supported_targets! { ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), + ("powerpc64-sony-ps3", powerpc64_sony_ps3), ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-sony-psx", mipsel_sony_psx), ("mipsel-unknown-none", mipsel_unknown_none), @@ -1862,6 +1863,7 @@ crate::target_spec_enum! { Nto = "nto", NuttX = "nuttx", OpenBsd = "openbsd", + Ps3 = "ps3", Psp = "psp", Psx = "psx", Qnx = "qnx", diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs new file mode 100644 index 0000000000000..41c8b3b206395 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs @@ -0,0 +1,107 @@ +use crate::spec::{ + Arch, Cc, CfgAbi, CodeModel, Endian, FramePointer, LinkerFlavor, Lld, LlvmAbi, Os, + PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &[ + // We strictly need ELFv1 PPC64. + "-m", + "elf64ppc", + // PS3 LV2 reserves the first 64KB page for unmapped memory protection. + "--image-base=0x10000", + // Should be default, but relying on automatic behavior appears to be brittle. + "-e", + "_start", + // CellOS expects .rodata to be merged into the executable Text segment (RX) + // so there are only 2 loadable segments (RX and RW) + "--no-rosegment", + // CellOS uses 64 KB memory pages. Without this flag, `mold` might align data segments to 4 KB boundaries. + "-z", + "separate-loadable-segments", + // Prevents mold from creating a `PT_GNU_RELRO` segment that GameOS does not support. + "-z", + "norelro", + // CellOS's loader doesn't behave like `ld`. PRXs are stubbed in the binary already. + "-Bstatic", + // The following are segments that might never be referenced by the code, + // but are expected to exist by the PS3's loader. + "-u", + "sys_process_param", + "-u", + "sys_proc_prx_param", + "--undefined-glob=*_prx_header", + "--undefined-glob=*_fnid_table", + "--undefined-glob=*_name", + "--undefined-glob=*_fstub_table", + ], + ); + + Target { + // LLVM will default to a compatible ELF backend. + llvm_target: "powerpc64-sony-ps3".into(), + + metadata: TargetMetadata { + description: Some("PowerPC64 (big endian) Sony PlayStation 3 (PS3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + + // We declare pointers to be 64-bit as the PPU _is_ a 64-bit core. + // However, for all real usage the OS limits us to **32-bit pointers**. + // SDKs should therefore take this into account, specifically when handling syscalls. + pointer_width: 64, + + data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64".into(), + arch: Arch::PowerPC64, + + options: TargetOptions { + // Base PS3 hardware. + vendor: "sony".into(), + endian: Endian::Big, + os: Os::Ps3, + cfg_abi: CfgAbi::ElfV1, + llvm_abiname: LlvmAbi::ElfV1, + features: "+altivec".into(), + + // CellOS requiring ELFv1 makes LLVM's `lld` incompatible. + // See: + // - [rust-lang/rust#85589](https://github.com/rust-lang/rust/issues/85589) + // - [llvm/llvm-project#27630](https://github.com/llvm/llvm-project/issues/27630) + linker: Some("mold".into()), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No), + + // CellOS _is_ case-sensitive, but the PS3's binaries vary + // in casing depending on whether they are games in `/dev_hdd0` + // or system binaries (such as PRX files). + // + // All games use the .ELF (uppercase) suffix, and Sony's own + // documentation and tools expect user app binaries to be uppercase. + exe_suffix: ".ELF".into(), + + // This limits us to 64KB of ToC, but yields smaller binaries and less assembly. + // Only becomes a problem for binaries with thousands of dependencies. + code_model: Some(CodeModel::Small), + // Prevents LLVM from emitting modern linker relaxation relocations. + relax_elf_relocations: false, + // CellOS main executables (`EBOOT.ELF`) **must be static executables** (ET_EXEC). + relocation_model: RelocModel::Static, + + // Locking defaults against future changes. + c_int_width: 32, + executables: true, + frame_pointer: FramePointer::MayOmit, + // Change this to `true` for developing kernel-mode applications. + // This target defaults to user-mode, and the kernel already handles + // this for us, so keeping it off is a performance gain. + disable_redzone: false, + + panic_strategy: PanicStrategy::Abort, + pre_link_args, + ..Default::default() + }, + } +} diff --git a/library/compiler-builtins/crates/symcheck/src/main.rs b/library/compiler-builtins/crates/symcheck/src/main.rs index a88aeed40fb0d..b5d5fecd63cb6 100644 --- a/library/compiler-builtins/crates/symcheck/src/main.rs +++ b/library/compiler-builtins/crates/symcheck/src/main.rs @@ -210,6 +210,7 @@ impl Target { "nto" => Os::Nto, "nuttx" => Os::Nuttx, "openbsd" => Os::OpenBsd, + "ps3" => Os::Ps3, "psp" => Os::Psp, "psx" => Os::Psx, "qurt" => Os::Qurt, @@ -324,6 +325,7 @@ enum Os { Nto, Nuttx, OpenBsd, + Ps3, Psp, Psx, Qurt, diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b9c79ab0128e9..f15c712c32b91 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -110,6 +110,7 @@ - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64-sony-ps3](platform-support/powerpc64-sony-ps3.md) - [powerpc64-unknown-linux-gnuelfv2](platform-support/powerpc64-unknown-linux-gnuelfv2.md) - [powerpc64-unknown-linux-musl](platform-support/powerpc64-unknown-linux-musl.md) - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7518ee9fabbbc..b34f4dd5b8874 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -388,6 +388,7 @@ target | std | host | notes [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) +[`powerpc64-sony-ps3`](platform-support/powerpc64-sony-ps3.md) | * | | PowerPC64 (BE) Sony PlayStation 3 (PS3) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) [`powerpc64-unknown-linux-gnuelfv2`](platform-support/powerpc64-unknown-linux-gnuelfv2.md) | ✓ | ✓ | PPC64 Linux (ELFv2 ABI, kernel 3.2, glibc 2.17) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 diff --git a/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md b/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md new file mode 100644 index 0000000000000..0c0c4327c355e --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64-sony-ps3.md @@ -0,0 +1,93 @@ +# `powerpc64-sony-ps3` + +**Tier: 3** + +Target for the Sony PlayStation 3 (shortened to "PS3"), for the PowerPC Processor Element (PPU) of the [Cell Broadband Engine Architecture (CBEA)](https://ieeexplore.ieee.org/document/5388675). + +## Target maintainers + +- [@ZephyrCodesStuff](https://github.com/ZephyrCodesStuff) (Primary developer and maintainer) +- [@RipleyTom](https://github.com/RipleyTom) (Fallback maintainer) + +## Requirements + +The target is a **big-endian PowerPC64 ELFv1** platform (the Cell Broadband Engine's PPE), and intended only for use on Sony PlayStation 3 systems, under the official operating system, "CellOS". + +The linker must support **Big-Endian PowerPC64 ELFv1**: the recommended and tested linker is [mold](https://github.com/rui314/mold). LLVM's `lld` does not correctly handle ELFv1 call relocations in freestanding `no_std` environments, making it incompatible. (See: [rust-lang/rust#85589](https://github.com/rust-lang/rust/issues/85589), [llvm/llvm-project#27630](https://github.com/llvm/llvm-project/issues/27630)) + +Resulting binaries require additional patching after linking to adhere to the PlayStation 3 operating system, in order to be bootable. An open-source patcher is available [here](https://github.com/ZephyrCodesStuff/rust-ps3/tree/main/moldier). Generally, a patcher must perform the following: + +- Rewrite the ELF OS/ABI to `0x66` (`ELFOSABI_CELLLV2`) +- Strip any GNU/Linux headers +- Add Sony-specific flags, sections (`.sys_proc_param` and `.sys_proc_prx_param`) and headers +- Add "stubs" for Sony SPRX dynamic-link libraries, by adding a section (`.lib.stub`) for CellOS to be able to link them +- Patch OPD function descriptors (in the `.opd` section) + +_**Note**: this list may not be exhaustive for all use cases, but is sufficient for producing a runnable binary. Producing a PRX dynamic library may require more/different steps._ + + +The target _fully supports_: + +- The Rust `core` features +- The Rust `alloc` feature, as the CellOS Lv2 kernel provides virtual memory allocation (`sys_memory_allocate`) on top of which a heap allocator (such as [talc](https://github.com/SFBdragon/talc)) can be implemented. +- AltiVec / VMX SIMD vector extensions (natively supported by LLVM via `+altivec`) + +## Building the target + +If `rustc` is built with this target enabled, no external C cross-compilation toolchain is strictly required to build the compiler host artifacts, but `mold` must be installed on the host system to perform linking. + +Support for using `lld` as a linker is unlikely, until support for ELFv1 is implemented on `lld`. + +## Building Rust programs + +Because this is a Tier 3 target, pre-compiled standard library artifacts (`core`, `alloc`) are not distributed via rustup. Programs must be built using a nightly toolchain with the `rust-src` component and `-Z build-std`. + +A Rust SDK ready for development exists open-sourced [here](https://github.com/Zephyrcodesstuff/rust-ps3) and is licensed `MIT OR Apache-2.0`. + +Configure your project `.cargo/config.toml`: +```toml +[target.powerpc64-sony-ps3] +linker = "mold" +rustflags = [ + "-C", "relocation-model=static", + "-C", "code-model=small", + "-C", "target-feature=+altivec", +] +``` + +**Prerequisites:** + +- A nightly Rust compiler with the `rust-src` component +- The [mold](https://github.com/rui314/mold) linker +- The [moldier](https://github.com/ZephyrCodesStuff/rust-ps3/tree/main/moldier) post-linker tool +- *(Optional)* `make_fself` or `scetool` for converting the output `.ELF` into an encrypted/signed `EBOOT.BIN` for running on real hardware. + +**Build process:** + +```bash +# Compile the binary +cargo +nightly build \ + --target powerpc64-sony-ps3 \ + -Z build-std=core,alloc \ + --release + +# Patch the linked executable +moldier patch target/powerpc64-sony-ps3/release/my_program.ELF + +# (Optional) Sign the binary for official hardware +make_fself "target/powerpc64-sony-ps3/release/my_program.ELF" "target/powerpc64-sony-ps3/release/my_program.BIN" +``` + +## Testing + +The target fully supports running binaries (once they're patched), both on official hardware and on [open-source emulators](https://github.com/rpcs3/rpcs3). + +As official firmware for the system forbids running unsigned code, the system must first be jailbroken in order to run binaries. This is not optional. + +Emulators do not impose any requirement regarding codesigning, thus testing on emulators is straightforward. + +Debugging is fully possible, either via debug firmware APIs on the official hardware, or on emulators via either their integrated debuggers, or a GDB server the emulator provides. + +## Cross-compilation toolchains and C code + +The target fully supports C/C++ code. Any compiler capable of producing binaries for a PowerPC64 big-endian processor can produce code to be embedded into the Rust program. diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 04c54e134b48e..db63dbaa24663 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -685,6 +685,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Nto => "QNX SDP 7.x", NuttX => "NuttX", OpenBsd => "OpenBSD", + Ps3 => "Play Station 3", Psp => "Play Station Portable", Psx => "Play Station 1", Qnx => "QNX SDP 8.0+", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index 1672e8e7930e3..c314b3f37c04d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -114,7 +114,7 @@ const KNOWN_ARCH: [&str; 20] = [ const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; -const KNOWN_OS: [&str; 20] = [ +const KNOWN_OS: [&str; 21] = [ "cuda", "dragonfly", "emscripten", @@ -128,6 +128,7 @@ const KNOWN_OS: [&str; 20] = [ "netbsd", "none", "openbsd", + "ps3", "psp", "redox", "solaris", diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 49bced1dd5bd2..beefbdb889940 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -403,6 +403,9 @@ //@ revisions: msp430_none_elf //@ [msp430_none_elf] compile-flags: --target msp430-none-elf //@ [msp430_none_elf] needs-llvm-components: msp430 +//@ revisions: powerpc64_sony_ps3 +//@ [powerpc64_sony_ps3] compile-flags: --target powerpc64-sony-ps3 +//@ [powerpc64_sony_ps3] needs-llvm-components: powerpc //@ revisions: powerpc64_unknown_freebsd //@ [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd //@ [powerpc64_unknown_freebsd] needs-llvm-components: powerpc diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index d5a8be83bc1d3..aec251878781e 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -79,11 +79,11 @@ pub fn bar() {} // Emscripten and ESP-IDF and FreeBSD and Fuchsia and GNU/Hurd and Haiku \ // and HelenOS and Hermit and Horizon and illumos and iOS and L4Re and Linux \ // and LynxOS-178 and macOS and Managarm and Motor OS and NetBSD and NuttX \ -// and OpenBSD and Play Station 1 and Play Station Portable and Play Station Vita \ -// and QNX SDP 7.x and QNX SDP 8.0+ and QuRT and Redox OS and RTEMS OS and Solaris and \ -// SOLID ASP3 and TEEOS and Trusty and tvOS and UEFI and VEXos and visionOS \ -// and VxWorks and WASI and watchOS and Windows and Xous and zero knowledge \ -// Virtual Machine only.' +// and OpenBSD and Play Station 1 and Play Station 3 and Play Station Portable \ +// and Play Station Vita and QNX SDP 7.x and QNX SDP 8.0+ and QuRT and Redox OS \ +// and RTEMS OS and Solaris and SOLID ASP3 and TEEOS and Trusty and tvOS and UEFI \ +// and VEXos and visionOS and VxWorks and WASI and watchOS and Windows and Xous \ +// and zero knowledge Virtual Machine only.' #[doc(cfg(all( target_os = "aix", target_os = "amdhsa", @@ -114,6 +114,7 @@ pub fn bar() {} target_os = "qnx", target_os = "nuttx", target_os = "openbsd", + target_os = "ps3", target_os = "psp", target_os = "psx", target_os = "qurt", diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr index 9bf3cef403159..d65562313cb42 100644 --- a/tests/ui/check-cfg/cfg-crate-features.stderr +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist` LL | #![cfg(not(target(os = "does_not_exist")))] | ^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, and `solaris` and 15 more + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, and `rtems` and 16 more = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 395a739b0be72..98404cd495dcf 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -232,7 +232,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -305,7 +305,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 31 warnings emitted From b1a9fcaead18811974a506eb75532e8e3b97c9a0 Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 12:59:14 +0200 Subject: [PATCH 33/40] alloc: a bunch of safety comments --- library/alloc/src/boxed.rs | 41 ++++++++++++++++++++--------- library/alloc/src/boxed/thin.rs | 19 ++++++++------ library/alloc/src/raw_vec/mod.rs | 44 +++++++++++++++++++------------- library/alloc/src/slice.rs | 25 ++++++++++++++---- 4 files changed, 86 insertions(+), 43 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 473f01660bdb4..d24c6aa617e8a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -923,7 +923,7 @@ impl Box<[T]> { #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit]> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `len` is exactly the capacity of this `RawVec`. unsafe { RawVec::with_capacity(len).into_box(len) } } @@ -947,7 +947,7 @@ impl Box<[T]> { #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `len` is exactly the capacity of this `RawVec`. unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } } @@ -981,7 +981,10 @@ impl Box<[T]> { }; Global.allocate(layout)?.cast() }; - // ignore-tidy-undocumented-unsafe + // SAFETY: `ptr` was just allocated with `Global` with the layout for an array of length + // `len`, and the layout creation would have failed if `len` overflowed an isize. + // `into_box` is sound to call since `len` corresponds to the length of the just-created + // `RawVec`. unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } @@ -1016,7 +1019,10 @@ impl Box<[T]> { }; Global.allocate_zeroed(layout)?.cast() }; - // ignore-tidy-undocumented-unsafe + // SAFETY: `ptr` was just allocated with `Global` with the layout for an array of length + // `len`, and the layout creation would have failed if `len` overflowed an isize. + // `into_box` is sound to call since `len` corresponds to the length of the just-created + // `RawVec`. unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } } @@ -1044,7 +1050,7 @@ impl Box<[T], A> { #[unstable(feature = "allocator_api", issue = "32838")] #[must_use] pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `len` is exactly the capacity of this `RawVec`. unsafe { RawVec::with_capacity_in(len, alloc).into_box(len) } } @@ -1072,7 +1078,7 @@ impl Box<[T], A> { #[unstable(feature = "allocator_api", issue = "32838")] #[must_use] pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `len` is exactly the capacity of this `RawVec`. unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) } } @@ -1111,7 +1117,10 @@ impl Box<[T], A> { }; alloc.allocate(layout)?.cast() }; - // ignore-tidy-undocumented-unsafe + // SAFETY: `ptr` was just allocated with `alloc` with the layout for an array of length + // `len`, and the layout creation would have failed if `len` overflowed an isize. + // `into_box` is sound to call since `len` corresponds to the length of the just-created + // `RawVec`. unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } } @@ -1151,7 +1160,10 @@ impl Box<[T], A> { }; alloc.allocate_zeroed(layout)?.cast() }; - // ignore-tidy-undocumented-unsafe + // SAFETY: `ptr` was just allocated with `alloc` with the layout for an array of length + // `len`, and the layout creation would have failed if `len` overflowed an isize. + // `into_box` is sound to call since `len` corresponds to the length of the just-created + // `RawVec`. unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } } @@ -2013,10 +2025,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { let ptr = self.0; - // ignore-tidy-undocumented-unsafe - unsafe { - let layout = Layout::for_value_raw(ptr.as_ptr()); - if layout.size() != 0 { + // SAFETY: The construction site of the unsized box had ensured for us that the + // allocation was made with a valid layout (the size does not overflow an isize, + // possibly because the size of the type is 0). + let layout = unsafe { Layout::for_value_raw(ptr.as_ptr()) }; + if layout.size() != 0 { + // SAFETY: Any nonzero allocation would have been created with the allocator + // of this box and `layout` would fit that allocation. We also are the only ones + // responsible for doing this deallocation and know that the pointer must be valid. + unsafe { self.1.deallocate(From::from(ptr.cast()), layout); } } diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index bef24fa822e6b..3d85956e6f200 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -167,7 +167,7 @@ impl Drop for ThinBox { fn drop(&mut self) { let value = self.deref_mut(); let value = value as *mut T; - // ignore-tidy-undocumented-unsafe + // SAFETY: `value` is valid for reads and writes for our `T`. unsafe { self.with_header().drop::(value); } @@ -249,7 +249,7 @@ impl WithHeader { debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); layout.dangling_ptr() } else { - // ignore-tidy-undocumented-unsafe + // SAFETY: We check above that the layout size is nonzero. let ptr = unsafe { alloc::alloc(layout) }; if ptr.is_null() { alloc::handle_alloc_error(layout); @@ -265,7 +265,8 @@ impl WithHeader { let result = WithHeader(ptr, PhantomData); - // ignore-tidy-undocumented-unsafe + // SAFETY: `result.header()` promises to give us a valid place for writing + // the header, and `result.value()` promises the same for the value. unsafe { ptr::write(result.header(), header); ptr::write(result.value().cast(), value); @@ -291,7 +292,7 @@ impl WithHeader { debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); layout.dangling_ptr() } else { - // ignore-tidy-undocumented-unsafe + // SAFETY: We check above that the layout size is nonzero. let ptr = unsafe { alloc::alloc(layout) }; if ptr.is_null() { return Err(core::alloc::AllocError); @@ -308,7 +309,8 @@ impl WithHeader { let result = WithHeader(ptr, PhantomData); - // ignore-tidy-undocumented-unsafe + // SAFETY: `result.header()` promises to give us a valid place for writing + // the header, and `result.value()` promises the same for the value. unsafe { ptr::write(result.header(), header); ptr::write(result.value().cast(), value); @@ -368,9 +370,10 @@ impl WithHeader { WithHeader(NonNull::new(value_ptr.cast()).unwrap(), PhantomData) } - // Safety: - // - Assumes that either `value` can be dereferenced, or is the - // `NonNull::dangling()` we use when both `T` and `H` are ZSTs. + /// # Safety + /// + /// Either `value` is valid for reads and writes, or it is `NonNull::dangling()` + /// if both `T` and `H` are ZSTs. unsafe fn drop(&self, value: *mut T) { struct DropGuard { ptr: NonNull, diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 250c666c70827..e5d9a46daf1a5 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -245,11 +245,13 @@ impl RawVec { ); let me = ManuallyDrop::new(self); - // ignore-tidy-undocumented-unsafe - unsafe { - let slice = me.ptr().cast::>().cast_slice(len); - Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) - } + let slice = me.ptr().cast::>().cast_slice(len); + // SAFETY: `slice` is a valid pointer for `len` `T`s, and the + // above `ManuallyDrop` ensures that the destructor of `me` which + // would free the allocation is never run. Moving the allocator + // out of `me.inner` is also sound since it is never accessed after + // this point. + unsafe { Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) } } /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. @@ -438,7 +440,7 @@ const impl RawVecInner { fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { - // ignore-tidy-undocumented-unsafe + // SAFETY: We already allocated at least `capacity`. unsafe { // Make it more obvious that a subsequent Vec::reserve(capacity) will not allocate. hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout)); @@ -482,7 +484,8 @@ const impl RawVecInner { // here should change to `ptr.len() / size_of::()`. Ok(Self { ptr: Unique::from(ptr.cast()), - // ignore-tidy-undocumented-unsafe + // SAFETY: We return early if `T` is a ZST, and if `capacity` would + // overflow an isize layout creation would have returned early as well. cap: unsafe { Cap::new_unchecked(capacity) }, alloc, }) @@ -554,7 +557,7 @@ const impl RawVecInner { ) -> Result, TryReserveError> { let new_layout = layout_array(cap, elem_layout)?; - // ignore-tidy-undocumented-unsafe + // SAFETY: Upheld by caller. let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { // FIXME(const-hack): switch to `debug_assert_eq` debug_assert!(old_layout.align() == new_layout.align()); @@ -644,7 +647,7 @@ impl RawVecInner { // and could hypothetically handle differences between stride and size, but this memory // has already been allocated so we know it can't overflow and currently Rust does not // support such types. So we can do better by skipping some checks and avoid an unwrap. - // ignore-tidy-undocumented-unsafe + // SAFETY: Upheld by caller, unless the element size is 0 which is checked against. unsafe { let alloc_size = elem_layout.size().unchecked_mul(self.cap.as_inner()); let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align()); @@ -678,7 +681,8 @@ impl RawVecInner { } if self.needs_to_grow(len, additional, elem_layout) { - // ignore-tidy-undocumented-unsafe + // SAFETY: `needs_to_grow` ensures that `len + additional` is greater than + // the current capacity, with the other preconditions upheld by our caller. unsafe { do_reserve_and_handle(self, len, additional, elem_layout); } @@ -701,7 +705,7 @@ impl RawVecInner { self.grow_amortized(len, additional, elem_layout)?; } } - // ignore-tidy-undocumented-unsafe + // SAFETY: If we've already grown, we will not need to again immediately after. unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); @@ -737,7 +741,7 @@ impl RawVecInner { self.grow_exact(len, additional, elem_layout)?; } } - // ignore-tidy-undocumented-unsafe + // SAFETY: If we've already grown, we will not need to again immediately after. unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); @@ -838,7 +842,8 @@ impl RawVecInner { /// big for LLVM to be willing to inline. /// /// # Safety - /// `cap <= self.capacity()` + /// - `cap <= self.capacity()` + /// - `elem_layout` must be valid for `self`. unsafe fn shrink_unchecked( &mut self, cap: usize, @@ -853,17 +858,20 @@ impl RawVecInner { // for the T::IS_ZST case since current_memory() will have returned // None. if cap == 0 { - // ignore-tidy-undocumented-unsafe + // SAFETY: T isn't a ZST if we're here and `ptr` is our pointer that `current_memory` + // ensures was allocated with `layout`. unsafe { self.alloc.deallocate(ptr, layout) }; self.ptr = - // ignore-tidy-undocumented-unsafe + // SAFETY: Alignment is guaranteed to be nonzero. unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) }; self.cap = ZERO_CAP; } else { - // ignore-tidy-undocumented-unsafe + // SAFETY: `cap` is less than the previous capacity, which must have fit in an + // isize already for the non-ZST case. `shrink` is also sound to call since + // `current_memory` ensures `ptr` and `layout` are correct for the old allocation, + // while `new_layout` is computed with a smaller size than the old one per the + // requirement we instate on our callers. let ptr = unsafe { - // Layout cannot overflow here because it would have - // overflowed earlier when capacity was larger. let new_size = elem_layout.size().unchecked_mul(cap); let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); self.alloc diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 47ed22c156515..057eb0f636abc 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -481,7 +481,10 @@ impl [T] { pub const fn into_vec(self: Box) -> Vec { let len = self.len(); let (b, alloc) = Box::into_raw_with_allocator(self); - // ignore-tidy-undocumented-unsafe + // SAFETY: `b` is currently allocated with `alloc` and was allocated with the + // matching layout for an array of `T * len`, the length is equal to the capacity, + // and the existence of a `Box<[T]>` is proof that the first `len` elements are + // valid `T`s. unsafe { Vec::from_raw_parts_in(b as *mut T, len, len, alloc) } } @@ -530,15 +533,21 @@ impl [T] { // If `m > 0`, there are remaining bits up to the leftmost '1'. while m > 0 { // `buf.extend(buf)`: - // ignore-tidy-undocumented-unsafe + // SAFETY: We're copying `len` elements after offsetting by `len`, + // with the previous call to `extend` ensuring that the first `len` + // elements are valid `T`s and the call to `with_capacity` ensuring + // we have `len * n` space to write the new elements. unsafe { ptr::copy_nonoverlapping::( buf.as_ptr(), (buf.as_mut_ptr()).add(buf.len()), buf.len(), ); - // `buf` has capacity of `self.len() * n`. - let buf_len = buf.len(); + } + // `buf` has capacity of `self.len() * n`. + let buf_len = buf.len(); + // SAFETY: We initialised another `buf_len` elements above. + unsafe { buf.set_len(buf_len * 2); } @@ -551,7 +560,13 @@ impl [T] { let rem_len = capacity - buf.len(); // `self.len() * rem` if rem_len > 0 { // `buf.extend(buf[0 .. rem_len])`: - // ignore-tidy-undocumented-unsafe + // SAFETY: We're copying `rem_len` elements after offsetting by `len`, + // with the previous `copy_nonverlapping` calls ensuring that the first `len` + // elements are valid `T`s and the call to `with_capacity` ensuring we have + // `rem_len` space to write the new elements. That is, these remaining `rem_len` + // elements must be preceded by more than `rem_len` previously-copied elements. + // Setting the length is correct since we've initialised the whole `capacity`-length + // space with copies of the previous `len` elements. unsafe { // This is non-overlapping since `2^expn > rem`. ptr::copy_nonoverlapping::( From 6cbd82c75f96b68a88d5bd63cdfe6cc7210e793d Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Fri, 4 Sep 2026 18:07:52 +0700 Subject: [PATCH 34/40] Add regression test from 1.98.1 --- ...run-impossible-predicates-post-analysis.rs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/ui/traits/object/rerun-impossible-predicates-post-analysis.rs diff --git a/tests/ui/traits/object/rerun-impossible-predicates-post-analysis.rs b/tests/ui/traits/object/rerun-impossible-predicates-post-analysis.rs new file mode 100644 index 0000000000000..232557c4a8a9d --- /dev/null +++ b/tests/ui/traits/object/rerun-impossible-predicates-post-analysis.rs @@ -0,0 +1,43 @@ +//@ run-pass + +// Regression test for #161441. This is a next-solver bug fixed by #158993 +// which affected stable due to `impossible_predicates` already using the next-solver +// by default. + +use std::marker::PhantomData; + +struct MyError; + +trait StreamingBody { + type BodyError; +} +struct Body; +impl StreamingBody for Body { + type BodyError = MyError; +} + +trait Service { + type Output; +} +struct HttpClientService; +impl Service for HttpClientService { + type Output = Body; +} + +trait Trait { + fn method(&self); +} +impl Trait for (F, PhantomData) +where + F: Fn() -> R, + HttpClientService: Service, + ResBody: StreamingBody, +{ + fn method(&self) {} +} + +fn inspect_websocket_message() -> impl Sized {} + +fn main() { + (&(inspect_websocket_message, PhantomData) as &dyn Trait).method(); +} From 22894e4c30a112be610bb85fc96b19ded87ae33a Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 13:13:29 +0200 Subject: [PATCH 35/40] reserve ahead of time --- library/alloc/src/string.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index f7613bc042a42..b363b6862f7e5 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2119,8 +2119,6 @@ impl String { where R: RangeBounds, { - use core::mem::DropGuard; - // We avoid #81138 (nondeterministic RangeBounds impls) because we only use `range` once, here. let checked_range = slice::range(range, ..self.len()); @@ -2133,12 +2131,15 @@ impl String { "end of range should be a character boundary" ); - let guard = DropGuard::new((), |_| core::process::abort_immediate()); + if replace_with.len() > checked_range.len() { + self.reserve(replace_with.len() - checked_range.len()); + } // SAFETY: We ensure that we're not replacing across a char boundary and - // that the new contents are valid UTF-8. We also protect against unwinds - // which may leave the string in an invalid state. + // that the new contents are valid UTF-8. The only potentially-unsound + // unwind from `splice` that would leave the string in an invalid state + // would be from an error growing the allocation, which we protect against + // by reserving it preemptively. unsafe { self.as_mut_vec() }.splice(checked_range, replace_with.bytes()); - DropGuard::dismiss(guard); } /// Replaces the leftmost occurrence of a pattern with another string, in-place. From 6072e6492b577f1c749d94346478bdd09bec7fb0 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Fri, 9 Jan 2026 22:53:40 +0000 Subject: [PATCH 36/40] rustc_index: Convenient debugging view of the IndexMap This small utility provides a familiar key-value view of an `IndexMap` in the debugging output. Co-authored-by: Dario Nieuwenhuis Signed-off-by: Xiangfei Ding --- compiler/rustc_index/src/vec.rs | 40 ++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 13f0dda180be9..97aad8e6e8c04 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -197,6 +197,11 @@ impl IndexVec { pub fn append(&mut self, other: &mut Self) { self.raw.append(&mut other.raw); } + + #[inline] + pub fn debug_map_view(&self) -> IndexSliceMapView<'_, I, T> { + IndexSliceMapView(self.as_slice()) + } } /// `IndexVec` is often used as a map, so it provides some map-like APIs. @@ -220,11 +225,44 @@ impl IndexVec> { pub fn contains(&self, index: I) -> bool { self.get(index).and_then(Option::as_ref).is_some() } + + /// This debug view will skip printing `None` entries. + /// This is useful when the slice is actually like a map and `None` means + /// a value is absent under that key. + #[inline] + pub fn debug_map_view_compact(&self) -> IndexSliceMapViewCompact<'_, I, T> { + IndexSliceMapViewCompact(self.as_slice()) + } } +pub struct IndexSliceMapView<'a, I: Idx, T>(&'a IndexSlice); +pub struct IndexSliceMapViewCompact<'a, I: Idx, T>(&'a IndexSlice>); + impl fmt::Debug for IndexVec { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.raw, fmt) + fmt::Debug::fmt(self.as_slice(), fmt) + } +} + +impl<'a, I: Idx, T: fmt::Debug> fmt::Debug for IndexSliceMapView<'a, I, T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut entries = fmt.debug_map(); + for (idx, val) in self.0.iter_enumerated() { + entries.entry(&idx, val); + } + entries.finish() + } +} + +impl<'a, I: Idx, T: fmt::Debug> fmt::Debug for IndexSliceMapViewCompact<'a, I, T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut entries = fmt.debug_map(); + for (idx, val) in self.0.iter_enumerated() { + if let Some(val) = val { + entries.entry(&idx, val); + } + } + entries.finish() } } From 1c48bd65b3c7bcf0aaa1fc36bb56cf6c483236de Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 14:12:07 +0200 Subject: [PATCH 37/40] review --- library/alloc/src/boxed/thin.rs | 4 ++-- library/alloc/src/raw_vec/mod.rs | 10 +++++++--- library/alloc/src/slice.rs | 18 ++++++++++-------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 3d85956e6f200..7d08991659787 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -372,8 +372,8 @@ impl WithHeader { /// # Safety /// - /// Either `value` is valid for reads and writes, or it is `NonNull::dangling()` - /// if both `T` and `H` are ZSTs. + /// `value` must point to an undropped owned `T`, and `self` must not be + /// accessed again after this is called. unsafe fn drop(&self, value: *mut T) { struct DropGuard { ptr: NonNull, diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index e5d9a46daf1a5..ffc92056cf464 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -248,9 +248,13 @@ impl RawVec { let slice = me.ptr().cast::>().cast_slice(len); // SAFETY: `slice` is a valid pointer for `len` `T`s, and the // above `ManuallyDrop` ensures that the destructor of `me` which - // would free the allocation is never run. Moving the allocator - // out of `me.inner` is also sound since it is never accessed after - // this point. + // would free the allocation is never run. The caller upholds that + // `len` meets or exceeds the last requested capacity, ensuring that + // the layout generated when dropping the resulting `Box` fits the + // allocation the `RawVec` created. + // + // Moving the allocator out of `me.inner` is also sound since it is + // never accessed after this point. unsafe { Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 057eb0f636abc..b7c288f5ad6c6 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -537,6 +537,9 @@ impl [T] { // with the previous call to `extend` ensuring that the first `len` // elements are valid `T`s and the call to `with_capacity` ensuring // we have `len * n` space to write the new elements. + // Each iteration of this loop doubles the number of initialised elements, + // which is tracked via `m` - when `m == 0`, we've written `most_significant_bit(n)` + // elements to the buffer. unsafe { ptr::copy_nonoverlapping::( buf.as_ptr(), @@ -547,9 +550,7 @@ impl [T] { // `buf` has capacity of `self.len() * n`. let buf_len = buf.len(); // SAFETY: We initialised another `buf_len` elements above. - unsafe { - buf.set_len(buf_len * 2); - } + unsafe { buf.set_len(buf_len * 2) }; m >>= 1; } @@ -560,11 +561,12 @@ impl [T] { let rem_len = capacity - buf.len(); // `self.len() * rem` if rem_len > 0 { // `buf.extend(buf[0 .. rem_len])`: - // SAFETY: We're copying `rem_len` elements after offsetting by `len`, - // with the previous `copy_nonverlapping` calls ensuring that the first `len` - // elements are valid `T`s and the call to `with_capacity` ensuring we have - // `rem_len` space to write the new elements. That is, these remaining `rem_len` - // elements must be preceded by more than `rem_len` previously-copied elements. + // SAFETY: We're copying `rem_len` elements after offsetting by `len`. The previous + // looping `copy_nonoverlapping` always doubled the number of instantiated elements, + // and so if `rem_len` was greater than `len` it would have allowed for another such + // doubling, until such time that `rem_len < len`. Thus, the space for these remainining + // `rem_len` elements must be preceded by more than `rem_len` previously-copied + // elements. // Setting the length is correct since we've initialised the whole `capacity`-length // space with copies of the previous `len` elements. unsafe { From c66f1501c9c05199e2a38e93e8d7b3a733117992 Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 14:13:47 +0200 Subject: [PATCH 38/40] drop unnecessary feature gate --- library/alloc/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index a016285112bab..89b15a169dce0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -90,7 +90,6 @@ // // Library features: // tidy-alphabetical-start -#![feature(abort_immediate)] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(ascii_char)] From e57809063d380b9e838c34b4c69925791572217e Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 4 Sep 2026 14:24:27 +0200 Subject: [PATCH 39/40] typo --- library/alloc/src/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index b7c288f5ad6c6..4741fe12ae89c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -564,7 +564,7 @@ impl [T] { // SAFETY: We're copying `rem_len` elements after offsetting by `len`. The previous // looping `copy_nonoverlapping` always doubled the number of instantiated elements, // and so if `rem_len` was greater than `len` it would have allowed for another such - // doubling, until such time that `rem_len < len`. Thus, the space for these remainining + // doubling, until such time that `rem_len < len`. Thus, the space for these remaining // `rem_len` elements must be preceded by more than `rem_len` previously-copied // elements. // Setting the length is correct since we've initialised the whole `capacity`-length From 3d6b9b4deeacc2c96c01009f002a173f36d29d8b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 4 Sep 2026 14:45:04 +0200 Subject: [PATCH 40/40] Update `askama` version to `0.16.1` --- Cargo.lock | 18 +++++++++--------- src/ci/citool/Cargo.lock | 18 +++++++++--------- src/ci/citool/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/clippy/Cargo.toml | 2 +- src/tools/generate-copyright/Cargo.toml | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b398d06c347df..f1ba6a1633615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,9 +198,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf825125edd887a019d0a3a837dcc5499a68b0d034cc3eb594070c3e18addc" +checksum = "6024d73179f43f15ccd2b881bfea6fee7f3a46ec53f33b52210dea749ebebaa4" dependencies = [ "askama_macros", "itoa", @@ -211,9 +211,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c7065972a130eafa84215f21352ae15b4a7393da48c1f5e103904490736738" +checksum = "071ee5ebf2138e3ad180e0aacf6940c2cab5e6d8333741d9925c7bee2b153f39" dependencies = [ "askama_parser", "basic-toml", @@ -224,23 +224,23 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "askama_macros" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e23b1d2c4bd39a41971f6124cef4cc6fd0540913ecb90919b69ab3bbe44ae1a" +checksum = "643e1c7cbb6aec1d920332fe51a7c0d8219e273dcb8602db03f5263e4d16487b" dependencies = [ "askama_derive", ] [[package]] name = "askama_parser" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db09fde9143e7ac4513358fb32ee32847125b63b18ea715afd487956da715da" +checksum = "2c5ae75772275d268b03ab8bdccdd12117b6169ee23256942b34e46c9f476583" dependencies = [ "rustc-hash 2.1.1", "serde", diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 4e0f51ee855e9..d6ffffb7b9f00 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -66,9 +66,9 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "askama" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf825125edd887a019d0a3a837dcc5499a68b0d034cc3eb594070c3e18addc" +checksum = "6024d73179f43f15ccd2b881bfea6fee7f3a46ec53f33b52210dea749ebebaa4" dependencies = [ "askama_macros", "itoa", @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c7065972a130eafa84215f21352ae15b4a7393da48c1f5e103904490736738" +checksum = "071ee5ebf2138e3ad180e0aacf6940c2cab5e6d8333741d9925c7bee2b153f39" dependencies = [ "askama_parser", "basic-toml", @@ -92,23 +92,23 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] name = "askama_macros" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e23b1d2c4bd39a41971f6124cef4cc6fd0540913ecb90919b69ab3bbe44ae1a" +checksum = "643e1c7cbb6aec1d920332fe51a7c0d8219e273dcb8602db03f5263e4d16487b" dependencies = [ "askama_derive", ] [[package]] name = "askama_parser" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db09fde9143e7ac4513358fb32ee32847125b63b18ea715afd487956da715da" +checksum = "2c5ae75772275d268b03ab8bdccdd12117b6169ee23256942b34e46c9f476583" dependencies = [ "rustc-hash", "serde", diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index 83d57b3294bbf..f7c3a8d9c8166 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] anyhow = "1" -askama = "0.16.0" +askama = "0.16.1" clap = { version = "4.5", features = ["derive"] } csv = "1" diff = "0.1" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1da46d9f6328a..19600ff2bb63e 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -askama = { version = "0.16.0", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.16.1", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" indexmap = { version = "2", features = ["serde"] } itertools = "0.15" diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index d83ebdcce2149..1dee95965ebd1 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -39,7 +39,7 @@ serde_json = "1.0.122" walkdir = "2.3" itertools = "0.15" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -askama = { version = "0.16.0", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.16.1", default-features = false, features = ["alloc", "config", "derive"] } [dev-dependencies.toml] version = "1.1" diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index 91236ff6c6040..b7c60266f98ca 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -8,7 +8,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" -askama = "0.16.0" +askama = "0.16.1" cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85"