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 868bc2a074a24d44adb8e2858219cd71a2ad522d Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Fri, 28 Aug 2026 22:47:24 +0000 Subject: [PATCH 15/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 16/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 17/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 18/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 19/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 b1e1bc99c16dc9cdea3265fc6bcce8514369f522 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 2 Sep 2026 11:35:45 +0800 Subject: [PATCH 20/40] bootstrap: use target's LLVM libdir when cross-compiling `Cargo::cargo` adds LLVM's library search path to `rustflags` for `ToolRustcPrivate`/`Codegen` so that tools linking against compiler libraries can find `libLLVM`. However, it always queried `host_llvm_config()`, which resolves to the *host*'s `llvm-config` regardless of the requested `target`. When cross-compiling, this appends the host's LLVM libdir to the target's link flags, which can cause linking to fail. Only use `llvm-config --libdir` when `target` is the host. Otherwise, ensure the `Llvm` step for `target` and derive the libdir from its `root_dir()` instead of invoking `llvm-config`, since the resulting binary may not be executable on the host if it was built for a different target. --- src/bootstrap/src/core/builder/cargo.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 3d16806a9581f..0a6ae88316f56 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -5,6 +5,7 @@ use std::{env, fs}; use super::{Builder, Kind}; use crate::core::build_steps::compile::is_lto_stage; +use crate::core::build_steps::llvm::Llvm; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; use crate::core::compiler::Compiler; @@ -1243,12 +1244,18 @@ impl Builder<'_> { if (mode == Mode::ToolRustcPrivate || mode == Mode::Codegen) && self.is_llvm_enabled_for(target) { - let llvm_libdir_raw = command(self.host_llvm_config()) - .cached() - .arg("--libdir") - .run_capture_stdout(self) - .stdout(); - let llvm_libdir = llvm_libdir_raw.trim(); + let llvm_libdir = if self.config.is_host_target(target) { + command(self.host_llvm_config()) + .cached() + .arg("--libdir") + .run_capture_stdout(self) + .stdout() + .trim() + .to_owned() + } else { + let llvm_output = self.ensure(Llvm { target }); + llvm_output.root_dir().join("lib").to_string_lossy().into_owned() + }; if target.is_msvc() { rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}")); } else { From 40c04ee8390ffccf67c67e7f2bb70d77175d4c35 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 2 Sep 2026 14:15:19 +1000 Subject: [PATCH 21/40] Move async tests into `tests/coverage/async` --- tests/coverage/{ => async}/async.cov-map | 0 tests/coverage/{ => async}/async.coverage | 0 tests/coverage/{ => async}/async.rs | 0 tests/coverage/{ => async}/async2.cov-map | 0 tests/coverage/{ => async}/async2.coverage | 0 tests/coverage/{ => async}/async2.rs | 0 tests/coverage/{ => async}/async_block.cov-map | 0 tests/coverage/{ => async}/async_block.coverage | 0 tests/coverage/{ => async}/async_block.rs | 0 tests/coverage/{ => async}/async_closure.cov-map | 0 tests/coverage/{ => async}/async_closure.coverage | 0 tests/coverage/{ => async}/async_closure.rs | 0 tests/coverage/{ => async}/async_closure2.cov-map | 0 tests/coverage/{ => async}/async_closure2.coverage | 0 tests/coverage/{ => async}/async_closure2.rs | 0 tests/coverage/{ => async}/auxiliary/executor.rs | 0 tests/coverage/{ => async}/await_ready.cov-map | 0 tests/coverage/{ => async}/await_ready.coverage | 0 tests/coverage/{ => async}/await_ready.rs | 0 tests/coverage/{ => async}/closure_macro_async.cov-map | 0 tests/coverage/{ => async}/closure_macro_async.coverage | 0 tests/coverage/{ => async}/closure_macro_async.rs | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename tests/coverage/{ => async}/async.cov-map (100%) rename tests/coverage/{ => async}/async.coverage (100%) rename tests/coverage/{ => async}/async.rs (100%) rename tests/coverage/{ => async}/async2.cov-map (100%) rename tests/coverage/{ => async}/async2.coverage (100%) rename tests/coverage/{ => async}/async2.rs (100%) rename tests/coverage/{ => async}/async_block.cov-map (100%) rename tests/coverage/{ => async}/async_block.coverage (100%) rename tests/coverage/{ => async}/async_block.rs (100%) rename tests/coverage/{ => async}/async_closure.cov-map (100%) rename tests/coverage/{ => async}/async_closure.coverage (100%) rename tests/coverage/{ => async}/async_closure.rs (100%) rename tests/coverage/{ => async}/async_closure2.cov-map (100%) rename tests/coverage/{ => async}/async_closure2.coverage (100%) rename tests/coverage/{ => async}/async_closure2.rs (100%) rename tests/coverage/{ => async}/auxiliary/executor.rs (100%) rename tests/coverage/{ => async}/await_ready.cov-map (100%) rename tests/coverage/{ => async}/await_ready.coverage (100%) rename tests/coverage/{ => async}/await_ready.rs (100%) rename tests/coverage/{ => async}/closure_macro_async.cov-map (100%) rename tests/coverage/{ => async}/closure_macro_async.coverage (100%) rename tests/coverage/{ => async}/closure_macro_async.rs (100%) diff --git a/tests/coverage/async.cov-map b/tests/coverage/async/async.cov-map similarity index 100% rename from tests/coverage/async.cov-map rename to tests/coverage/async/async.cov-map diff --git a/tests/coverage/async.coverage b/tests/coverage/async/async.coverage similarity index 100% rename from tests/coverage/async.coverage rename to tests/coverage/async/async.coverage diff --git a/tests/coverage/async.rs b/tests/coverage/async/async.rs similarity index 100% rename from tests/coverage/async.rs rename to tests/coverage/async/async.rs diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async/async2.cov-map similarity index 100% rename from tests/coverage/async2.cov-map rename to tests/coverage/async/async2.cov-map diff --git a/tests/coverage/async2.coverage b/tests/coverage/async/async2.coverage similarity index 100% rename from tests/coverage/async2.coverage rename to tests/coverage/async/async2.coverage diff --git a/tests/coverage/async2.rs b/tests/coverage/async/async2.rs similarity index 100% rename from tests/coverage/async2.rs rename to tests/coverage/async/async2.rs diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async/async_block.cov-map similarity index 100% rename from tests/coverage/async_block.cov-map rename to tests/coverage/async/async_block.cov-map diff --git a/tests/coverage/async_block.coverage b/tests/coverage/async/async_block.coverage similarity index 100% rename from tests/coverage/async_block.coverage rename to tests/coverage/async/async_block.coverage diff --git a/tests/coverage/async_block.rs b/tests/coverage/async/async_block.rs similarity index 100% rename from tests/coverage/async_block.rs rename to tests/coverage/async/async_block.rs diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async/async_closure.cov-map similarity index 100% rename from tests/coverage/async_closure.cov-map rename to tests/coverage/async/async_closure.cov-map diff --git a/tests/coverage/async_closure.coverage b/tests/coverage/async/async_closure.coverage similarity index 100% rename from tests/coverage/async_closure.coverage rename to tests/coverage/async/async_closure.coverage diff --git a/tests/coverage/async_closure.rs b/tests/coverage/async/async_closure.rs similarity index 100% rename from tests/coverage/async_closure.rs rename to tests/coverage/async/async_closure.rs diff --git a/tests/coverage/async_closure2.cov-map b/tests/coverage/async/async_closure2.cov-map similarity index 100% rename from tests/coverage/async_closure2.cov-map rename to tests/coverage/async/async_closure2.cov-map diff --git a/tests/coverage/async_closure2.coverage b/tests/coverage/async/async_closure2.coverage similarity index 100% rename from tests/coverage/async_closure2.coverage rename to tests/coverage/async/async_closure2.coverage diff --git a/tests/coverage/async_closure2.rs b/tests/coverage/async/async_closure2.rs similarity index 100% rename from tests/coverage/async_closure2.rs rename to tests/coverage/async/async_closure2.rs diff --git a/tests/coverage/auxiliary/executor.rs b/tests/coverage/async/auxiliary/executor.rs similarity index 100% rename from tests/coverage/auxiliary/executor.rs rename to tests/coverage/async/auxiliary/executor.rs diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/async/await_ready.cov-map similarity index 100% rename from tests/coverage/await_ready.cov-map rename to tests/coverage/async/await_ready.cov-map diff --git a/tests/coverage/await_ready.coverage b/tests/coverage/async/await_ready.coverage similarity index 100% rename from tests/coverage/await_ready.coverage rename to tests/coverage/async/await_ready.coverage diff --git a/tests/coverage/await_ready.rs b/tests/coverage/async/await_ready.rs similarity index 100% rename from tests/coverage/await_ready.rs rename to tests/coverage/async/await_ready.rs diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/async/closure_macro_async.cov-map similarity index 100% rename from tests/coverage/closure_macro_async.cov-map rename to tests/coverage/async/closure_macro_async.cov-map diff --git a/tests/coverage/closure_macro_async.coverage b/tests/coverage/async/closure_macro_async.coverage similarity index 100% rename from tests/coverage/closure_macro_async.coverage rename to tests/coverage/async/closure_macro_async.coverage diff --git a/tests/coverage/closure_macro_async.rs b/tests/coverage/async/closure_macro_async.rs similarity index 100% rename from tests/coverage/closure_macro_async.rs rename to tests/coverage/async/closure_macro_async.rs From c7c0eeaa3a4be33afc4770974f34983963bd0a5f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 2 Sep 2026 14:15:19 +1000 Subject: [PATCH 22/40] Move some less-useful tests into `tests/coverage/iffy` These tests are of limited value for investigating specific problems, but still have some worth in detecting regressions by adding variety to the test corpus. (The boundary is a bit fuzzy, but it's easy enough to move tests back out if appropriate.) --- tests/coverage/iffy/README.md | 4 ++++ tests/coverage/{ => iffy}/abort.cov-map | 0 tests/coverage/{ => iffy}/abort.coverage | 0 tests/coverage/{ => iffy}/abort.rs | 0 tests/coverage/{ => iffy}/assert.cov-map | 0 tests/coverage/{ => iffy}/assert.coverage | 0 tests/coverage/{ => iffy}/assert.rs | 0 .../{ => iffy}/auxiliary/inline_always_with_dead_code.rs | 0 tests/coverage/{ => iffy}/auxiliary/used_crate.rs | 0 tests/coverage/{ => iffy}/auxiliary/used_inline_crate.rs | 0 tests/coverage/{ => iffy}/closure.cov-map | 0 tests/coverage/{ => iffy}/closure.coverage | 0 tests/coverage/{ => iffy}/closure.rs | 0 tests/coverage/{ => iffy}/closure_macro.cov-map | 0 tests/coverage/{ => iffy}/closure_macro.coverage | 0 tests/coverage/{ => iffy}/closure_macro.rs | 0 tests/coverage/{ => iffy}/conditions.cov-map | 0 tests/coverage/{ => iffy}/conditions.coverage | 0 tests/coverage/{ => iffy}/conditions.rs | 0 tests/coverage/{ => iffy}/continue.cov-map | 0 tests/coverage/{ => iffy}/continue.coverage | 0 tests/coverage/{ => iffy}/continue.rs | 0 tests/coverage/{ => iffy}/coroutine.cov-map | 0 tests/coverage/{ => iffy}/coroutine.coverage | 0 tests/coverage/{ => iffy}/coroutine.rs | 0 tests/coverage/{ => iffy}/drop_trait.cov-map | 0 tests/coverage/{ => iffy}/drop_trait.coverage | 0 tests/coverage/{ => iffy}/drop_trait.rs | 0 tests/coverage/{ => iffy}/generics.cov-map | 0 tests/coverage/{ => iffy}/generics.coverage | 0 tests/coverage/{ => iffy}/generics.rs | 0 tests/coverage/{ => iffy}/if.cov-map | 0 tests/coverage/{ => iffy}/if.coverage | 0 tests/coverage/{ => iffy}/if.rs | 0 tests/coverage/{ => iffy}/if_else.cov-map | 0 tests/coverage/{ => iffy}/if_else.coverage | 0 tests/coverage/{ => iffy}/if_else.rs | 0 tests/coverage/{ => iffy}/inline-dead.cov-map | 0 tests/coverage/{ => iffy}/inline-dead.coverage | 0 tests/coverage/{ => iffy}/inline-dead.rs | 0 tests/coverage/{ => iffy}/inline.cov-map | 0 tests/coverage/{ => iffy}/inline.coverage | 0 tests/coverage/{ => iffy}/inline.rs | 0 tests/coverage/{ => iffy}/inner_items.cov-map | 0 tests/coverage/{ => iffy}/inner_items.coverage | 0 tests/coverage/{ => iffy}/inner_items.rs | 0 tests/coverage/{ => iffy}/issue-83601.cov-map | 0 tests/coverage/{ => iffy}/issue-83601.coverage | 0 tests/coverage/{ => iffy}/issue-83601.rs | 0 tests/coverage/{ => iffy}/issue-84561.cov-map | 0 tests/coverage/{ => iffy}/issue-84561.coverage | 0 tests/coverage/{ => iffy}/issue-84561.rs | 0 tests/coverage/{ => iffy}/issue-85461.cov-map | 0 tests/coverage/{ => iffy}/issue-85461.coverage | 0 tests/coverage/{ => iffy}/issue-85461.rs | 0 tests/coverage/{ => iffy}/issue-93054.cov-map | 0 tests/coverage/{ => iffy}/issue-93054.coverage | 0 tests/coverage/{ => iffy}/issue-93054.rs | 0 tests/coverage/{ => iffy}/lazy_boolean.cov-map | 0 tests/coverage/{ => iffy}/lazy_boolean.coverage | 0 tests/coverage/{ => iffy}/lazy_boolean.rs | 0 tests/coverage/{ => iffy}/loops_branches.cov-map | 0 tests/coverage/{ => iffy}/loops_branches.coverage | 0 tests/coverage/{ => iffy}/loops_branches.rs | 0 tests/coverage/{ => iffy}/match_or_pattern.cov-map | 0 tests/coverage/{ => iffy}/match_or_pattern.coverage | 0 tests/coverage/{ => iffy}/match_or_pattern.rs | 0 tests/coverage/{ => iffy}/nested_loops.cov-map | 0 tests/coverage/{ => iffy}/nested_loops.coverage | 0 tests/coverage/{ => iffy}/nested_loops.rs | 0 tests/coverage/{ => iffy}/no_cov_crate.cov-map | 0 tests/coverage/{ => iffy}/no_cov_crate.coverage | 0 tests/coverage/{ => iffy}/no_cov_crate.rs | 0 tests/coverage/{ => iffy}/overflow.cov-map | 0 tests/coverage/{ => iffy}/overflow.coverage | 0 tests/coverage/{ => iffy}/overflow.rs | 0 tests/coverage/{ => iffy}/panic_unwind.cov-map | 0 tests/coverage/{ => iffy}/panic_unwind.coverage | 0 tests/coverage/{ => iffy}/panic_unwind.rs | 0 tests/coverage/{ => iffy}/partial_eq.cov-map | 0 tests/coverage/{ => iffy}/partial_eq.coverage | 0 tests/coverage/{ => iffy}/partial_eq.rs | 0 tests/coverage/{ => iffy}/simple_loop.cov-map | 0 tests/coverage/{ => iffy}/simple_loop.coverage | 0 tests/coverage/{ => iffy}/simple_loop.rs | 0 tests/coverage/{ => iffy}/simple_match.cov-map | 0 tests/coverage/{ => iffy}/simple_match.coverage | 0 tests/coverage/{ => iffy}/simple_match.rs | 0 tests/coverage/{ => iffy}/try_error_result.cov-map | 0 tests/coverage/{ => iffy}/try_error_result.coverage | 0 tests/coverage/{ => iffy}/try_error_result.rs | 0 tests/coverage/{ => iffy}/uses_crate.cov-map | 0 tests/coverage/{ => iffy}/uses_crate.coverage | 0 tests/coverage/{ => iffy}/uses_crate.rs | 0 tests/coverage/{ => iffy}/uses_inline_crate.cov-map | 0 tests/coverage/{ => iffy}/uses_inline_crate.coverage | 0 tests/coverage/{ => iffy}/uses_inline_crate.rs | 0 tests/coverage/{ => iffy}/while.cov-map | 0 tests/coverage/{ => iffy}/while.coverage | 0 tests/coverage/{ => iffy}/while.rs | 0 tests/coverage/{ => iffy}/while_early_ret.cov-map | 0 tests/coverage/{ => iffy}/while_early_ret.coverage | 0 tests/coverage/{ => iffy}/while_early_ret.rs | 0 tests/coverage/{ => iffy}/yield.cov-map | 0 tests/coverage/{ => iffy}/yield.coverage | 0 tests/coverage/{ => iffy}/yield.rs | 0 106 files changed, 4 insertions(+) create mode 100644 tests/coverage/iffy/README.md rename tests/coverage/{ => iffy}/abort.cov-map (100%) rename tests/coverage/{ => iffy}/abort.coverage (100%) rename tests/coverage/{ => iffy}/abort.rs (100%) rename tests/coverage/{ => iffy}/assert.cov-map (100%) rename tests/coverage/{ => iffy}/assert.coverage (100%) rename tests/coverage/{ => iffy}/assert.rs (100%) rename tests/coverage/{ => iffy}/auxiliary/inline_always_with_dead_code.rs (100%) rename tests/coverage/{ => iffy}/auxiliary/used_crate.rs (100%) rename tests/coverage/{ => iffy}/auxiliary/used_inline_crate.rs (100%) rename tests/coverage/{ => iffy}/closure.cov-map (100%) rename tests/coverage/{ => iffy}/closure.coverage (100%) rename tests/coverage/{ => iffy}/closure.rs (100%) rename tests/coverage/{ => iffy}/closure_macro.cov-map (100%) rename tests/coverage/{ => iffy}/closure_macro.coverage (100%) rename tests/coverage/{ => iffy}/closure_macro.rs (100%) rename tests/coverage/{ => iffy}/conditions.cov-map (100%) rename tests/coverage/{ => iffy}/conditions.coverage (100%) rename tests/coverage/{ => iffy}/conditions.rs (100%) rename tests/coverage/{ => iffy}/continue.cov-map (100%) rename tests/coverage/{ => iffy}/continue.coverage (100%) rename tests/coverage/{ => iffy}/continue.rs (100%) rename tests/coverage/{ => iffy}/coroutine.cov-map (100%) rename tests/coverage/{ => iffy}/coroutine.coverage (100%) rename tests/coverage/{ => iffy}/coroutine.rs (100%) rename tests/coverage/{ => iffy}/drop_trait.cov-map (100%) rename tests/coverage/{ => iffy}/drop_trait.coverage (100%) rename tests/coverage/{ => iffy}/drop_trait.rs (100%) rename tests/coverage/{ => iffy}/generics.cov-map (100%) rename tests/coverage/{ => iffy}/generics.coverage (100%) rename tests/coverage/{ => iffy}/generics.rs (100%) rename tests/coverage/{ => iffy}/if.cov-map (100%) rename tests/coverage/{ => iffy}/if.coverage (100%) rename tests/coverage/{ => iffy}/if.rs (100%) rename tests/coverage/{ => iffy}/if_else.cov-map (100%) rename tests/coverage/{ => iffy}/if_else.coverage (100%) rename tests/coverage/{ => iffy}/if_else.rs (100%) rename tests/coverage/{ => iffy}/inline-dead.cov-map (100%) rename tests/coverage/{ => iffy}/inline-dead.coverage (100%) rename tests/coverage/{ => iffy}/inline-dead.rs (100%) rename tests/coverage/{ => iffy}/inline.cov-map (100%) rename tests/coverage/{ => iffy}/inline.coverage (100%) rename tests/coverage/{ => iffy}/inline.rs (100%) rename tests/coverage/{ => iffy}/inner_items.cov-map (100%) rename tests/coverage/{ => iffy}/inner_items.coverage (100%) rename tests/coverage/{ => iffy}/inner_items.rs (100%) rename tests/coverage/{ => iffy}/issue-83601.cov-map (100%) rename tests/coverage/{ => iffy}/issue-83601.coverage (100%) rename tests/coverage/{ => iffy}/issue-83601.rs (100%) rename tests/coverage/{ => iffy}/issue-84561.cov-map (100%) rename tests/coverage/{ => iffy}/issue-84561.coverage (100%) rename tests/coverage/{ => iffy}/issue-84561.rs (100%) rename tests/coverage/{ => iffy}/issue-85461.cov-map (100%) rename tests/coverage/{ => iffy}/issue-85461.coverage (100%) rename tests/coverage/{ => iffy}/issue-85461.rs (100%) rename tests/coverage/{ => iffy}/issue-93054.cov-map (100%) rename tests/coverage/{ => iffy}/issue-93054.coverage (100%) rename tests/coverage/{ => iffy}/issue-93054.rs (100%) rename tests/coverage/{ => iffy}/lazy_boolean.cov-map (100%) rename tests/coverage/{ => iffy}/lazy_boolean.coverage (100%) rename tests/coverage/{ => iffy}/lazy_boolean.rs (100%) rename tests/coverage/{ => iffy}/loops_branches.cov-map (100%) rename tests/coverage/{ => iffy}/loops_branches.coverage (100%) rename tests/coverage/{ => iffy}/loops_branches.rs (100%) rename tests/coverage/{ => iffy}/match_or_pattern.cov-map (100%) rename tests/coverage/{ => iffy}/match_or_pattern.coverage (100%) rename tests/coverage/{ => iffy}/match_or_pattern.rs (100%) rename tests/coverage/{ => iffy}/nested_loops.cov-map (100%) rename tests/coverage/{ => iffy}/nested_loops.coverage (100%) rename tests/coverage/{ => iffy}/nested_loops.rs (100%) rename tests/coverage/{ => iffy}/no_cov_crate.cov-map (100%) rename tests/coverage/{ => iffy}/no_cov_crate.coverage (100%) rename tests/coverage/{ => iffy}/no_cov_crate.rs (100%) rename tests/coverage/{ => iffy}/overflow.cov-map (100%) rename tests/coverage/{ => iffy}/overflow.coverage (100%) rename tests/coverage/{ => iffy}/overflow.rs (100%) rename tests/coverage/{ => iffy}/panic_unwind.cov-map (100%) rename tests/coverage/{ => iffy}/panic_unwind.coverage (100%) rename tests/coverage/{ => iffy}/panic_unwind.rs (100%) rename tests/coverage/{ => iffy}/partial_eq.cov-map (100%) rename tests/coverage/{ => iffy}/partial_eq.coverage (100%) rename tests/coverage/{ => iffy}/partial_eq.rs (100%) rename tests/coverage/{ => iffy}/simple_loop.cov-map (100%) rename tests/coverage/{ => iffy}/simple_loop.coverage (100%) rename tests/coverage/{ => iffy}/simple_loop.rs (100%) rename tests/coverage/{ => iffy}/simple_match.cov-map (100%) rename tests/coverage/{ => iffy}/simple_match.coverage (100%) rename tests/coverage/{ => iffy}/simple_match.rs (100%) rename tests/coverage/{ => iffy}/try_error_result.cov-map (100%) rename tests/coverage/{ => iffy}/try_error_result.coverage (100%) rename tests/coverage/{ => iffy}/try_error_result.rs (100%) rename tests/coverage/{ => iffy}/uses_crate.cov-map (100%) rename tests/coverage/{ => iffy}/uses_crate.coverage (100%) rename tests/coverage/{ => iffy}/uses_crate.rs (100%) rename tests/coverage/{ => iffy}/uses_inline_crate.cov-map (100%) rename tests/coverage/{ => iffy}/uses_inline_crate.coverage (100%) rename tests/coverage/{ => iffy}/uses_inline_crate.rs (100%) rename tests/coverage/{ => iffy}/while.cov-map (100%) rename tests/coverage/{ => iffy}/while.coverage (100%) rename tests/coverage/{ => iffy}/while.rs (100%) rename tests/coverage/{ => iffy}/while_early_ret.cov-map (100%) rename tests/coverage/{ => iffy}/while_early_ret.coverage (100%) rename tests/coverage/{ => iffy}/while_early_ret.rs (100%) rename tests/coverage/{ => iffy}/yield.cov-map (100%) rename tests/coverage/{ => iffy}/yield.coverage (100%) rename tests/coverage/{ => iffy}/yield.rs (100%) diff --git a/tests/coverage/iffy/README.md b/tests/coverage/iffy/README.md new file mode 100644 index 0000000000000..0d8a866ed2685 --- /dev/null +++ b/tests/coverage/iffy/README.md @@ -0,0 +1,4 @@ +# `tests/coverage/iffy` + +Older tests that are of limited value for investigating specific problems, +but still have some worth in detecting regressions by adding variety to the test corpus. diff --git a/tests/coverage/abort.cov-map b/tests/coverage/iffy/abort.cov-map similarity index 100% rename from tests/coverage/abort.cov-map rename to tests/coverage/iffy/abort.cov-map diff --git a/tests/coverage/abort.coverage b/tests/coverage/iffy/abort.coverage similarity index 100% rename from tests/coverage/abort.coverage rename to tests/coverage/iffy/abort.coverage diff --git a/tests/coverage/abort.rs b/tests/coverage/iffy/abort.rs similarity index 100% rename from tests/coverage/abort.rs rename to tests/coverage/iffy/abort.rs diff --git a/tests/coverage/assert.cov-map b/tests/coverage/iffy/assert.cov-map similarity index 100% rename from tests/coverage/assert.cov-map rename to tests/coverage/iffy/assert.cov-map diff --git a/tests/coverage/assert.coverage b/tests/coverage/iffy/assert.coverage similarity index 100% rename from tests/coverage/assert.coverage rename to tests/coverage/iffy/assert.coverage diff --git a/tests/coverage/assert.rs b/tests/coverage/iffy/assert.rs similarity index 100% rename from tests/coverage/assert.rs rename to tests/coverage/iffy/assert.rs diff --git a/tests/coverage/auxiliary/inline_always_with_dead_code.rs b/tests/coverage/iffy/auxiliary/inline_always_with_dead_code.rs similarity index 100% rename from tests/coverage/auxiliary/inline_always_with_dead_code.rs rename to tests/coverage/iffy/auxiliary/inline_always_with_dead_code.rs diff --git a/tests/coverage/auxiliary/used_crate.rs b/tests/coverage/iffy/auxiliary/used_crate.rs similarity index 100% rename from tests/coverage/auxiliary/used_crate.rs rename to tests/coverage/iffy/auxiliary/used_crate.rs diff --git a/tests/coverage/auxiliary/used_inline_crate.rs b/tests/coverage/iffy/auxiliary/used_inline_crate.rs similarity index 100% rename from tests/coverage/auxiliary/used_inline_crate.rs rename to tests/coverage/iffy/auxiliary/used_inline_crate.rs diff --git a/tests/coverage/closure.cov-map b/tests/coverage/iffy/closure.cov-map similarity index 100% rename from tests/coverage/closure.cov-map rename to tests/coverage/iffy/closure.cov-map diff --git a/tests/coverage/closure.coverage b/tests/coverage/iffy/closure.coverage similarity index 100% rename from tests/coverage/closure.coverage rename to tests/coverage/iffy/closure.coverage diff --git a/tests/coverage/closure.rs b/tests/coverage/iffy/closure.rs similarity index 100% rename from tests/coverage/closure.rs rename to tests/coverage/iffy/closure.rs diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/iffy/closure_macro.cov-map similarity index 100% rename from tests/coverage/closure_macro.cov-map rename to tests/coverage/iffy/closure_macro.cov-map diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/iffy/closure_macro.coverage similarity index 100% rename from tests/coverage/closure_macro.coverage rename to tests/coverage/iffy/closure_macro.coverage diff --git a/tests/coverage/closure_macro.rs b/tests/coverage/iffy/closure_macro.rs similarity index 100% rename from tests/coverage/closure_macro.rs rename to tests/coverage/iffy/closure_macro.rs diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/iffy/conditions.cov-map similarity index 100% rename from tests/coverage/conditions.cov-map rename to tests/coverage/iffy/conditions.cov-map diff --git a/tests/coverage/conditions.coverage b/tests/coverage/iffy/conditions.coverage similarity index 100% rename from tests/coverage/conditions.coverage rename to tests/coverage/iffy/conditions.coverage diff --git a/tests/coverage/conditions.rs b/tests/coverage/iffy/conditions.rs similarity index 100% rename from tests/coverage/conditions.rs rename to tests/coverage/iffy/conditions.rs diff --git a/tests/coverage/continue.cov-map b/tests/coverage/iffy/continue.cov-map similarity index 100% rename from tests/coverage/continue.cov-map rename to tests/coverage/iffy/continue.cov-map diff --git a/tests/coverage/continue.coverage b/tests/coverage/iffy/continue.coverage similarity index 100% rename from tests/coverage/continue.coverage rename to tests/coverage/iffy/continue.coverage diff --git a/tests/coverage/continue.rs b/tests/coverage/iffy/continue.rs similarity index 100% rename from tests/coverage/continue.rs rename to tests/coverage/iffy/continue.rs diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/iffy/coroutine.cov-map similarity index 100% rename from tests/coverage/coroutine.cov-map rename to tests/coverage/iffy/coroutine.cov-map diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/iffy/coroutine.coverage similarity index 100% rename from tests/coverage/coroutine.coverage rename to tests/coverage/iffy/coroutine.coverage diff --git a/tests/coverage/coroutine.rs b/tests/coverage/iffy/coroutine.rs similarity index 100% rename from tests/coverage/coroutine.rs rename to tests/coverage/iffy/coroutine.rs diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/iffy/drop_trait.cov-map similarity index 100% rename from tests/coverage/drop_trait.cov-map rename to tests/coverage/iffy/drop_trait.cov-map diff --git a/tests/coverage/drop_trait.coverage b/tests/coverage/iffy/drop_trait.coverage similarity index 100% rename from tests/coverage/drop_trait.coverage rename to tests/coverage/iffy/drop_trait.coverage diff --git a/tests/coverage/drop_trait.rs b/tests/coverage/iffy/drop_trait.rs similarity index 100% rename from tests/coverage/drop_trait.rs rename to tests/coverage/iffy/drop_trait.rs diff --git a/tests/coverage/generics.cov-map b/tests/coverage/iffy/generics.cov-map similarity index 100% rename from tests/coverage/generics.cov-map rename to tests/coverage/iffy/generics.cov-map diff --git a/tests/coverage/generics.coverage b/tests/coverage/iffy/generics.coverage similarity index 100% rename from tests/coverage/generics.coverage rename to tests/coverage/iffy/generics.coverage diff --git a/tests/coverage/generics.rs b/tests/coverage/iffy/generics.rs similarity index 100% rename from tests/coverage/generics.rs rename to tests/coverage/iffy/generics.rs diff --git a/tests/coverage/if.cov-map b/tests/coverage/iffy/if.cov-map similarity index 100% rename from tests/coverage/if.cov-map rename to tests/coverage/iffy/if.cov-map diff --git a/tests/coverage/if.coverage b/tests/coverage/iffy/if.coverage similarity index 100% rename from tests/coverage/if.coverage rename to tests/coverage/iffy/if.coverage diff --git a/tests/coverage/if.rs b/tests/coverage/iffy/if.rs similarity index 100% rename from tests/coverage/if.rs rename to tests/coverage/iffy/if.rs diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/iffy/if_else.cov-map similarity index 100% rename from tests/coverage/if_else.cov-map rename to tests/coverage/iffy/if_else.cov-map diff --git a/tests/coverage/if_else.coverage b/tests/coverage/iffy/if_else.coverage similarity index 100% rename from tests/coverage/if_else.coverage rename to tests/coverage/iffy/if_else.coverage diff --git a/tests/coverage/if_else.rs b/tests/coverage/iffy/if_else.rs similarity index 100% rename from tests/coverage/if_else.rs rename to tests/coverage/iffy/if_else.rs diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/iffy/inline-dead.cov-map similarity index 100% rename from tests/coverage/inline-dead.cov-map rename to tests/coverage/iffy/inline-dead.cov-map diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/iffy/inline-dead.coverage similarity index 100% rename from tests/coverage/inline-dead.coverage rename to tests/coverage/iffy/inline-dead.coverage diff --git a/tests/coverage/inline-dead.rs b/tests/coverage/iffy/inline-dead.rs similarity index 100% rename from tests/coverage/inline-dead.rs rename to tests/coverage/iffy/inline-dead.rs diff --git a/tests/coverage/inline.cov-map b/tests/coverage/iffy/inline.cov-map similarity index 100% rename from tests/coverage/inline.cov-map rename to tests/coverage/iffy/inline.cov-map diff --git a/tests/coverage/inline.coverage b/tests/coverage/iffy/inline.coverage similarity index 100% rename from tests/coverage/inline.coverage rename to tests/coverage/iffy/inline.coverage diff --git a/tests/coverage/inline.rs b/tests/coverage/iffy/inline.rs similarity index 100% rename from tests/coverage/inline.rs rename to tests/coverage/iffy/inline.rs diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/iffy/inner_items.cov-map similarity index 100% rename from tests/coverage/inner_items.cov-map rename to tests/coverage/iffy/inner_items.cov-map diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/iffy/inner_items.coverage similarity index 100% rename from tests/coverage/inner_items.coverage rename to tests/coverage/iffy/inner_items.coverage diff --git a/tests/coverage/inner_items.rs b/tests/coverage/iffy/inner_items.rs similarity index 100% rename from tests/coverage/inner_items.rs rename to tests/coverage/iffy/inner_items.rs diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/iffy/issue-83601.cov-map similarity index 100% rename from tests/coverage/issue-83601.cov-map rename to tests/coverage/iffy/issue-83601.cov-map diff --git a/tests/coverage/issue-83601.coverage b/tests/coverage/iffy/issue-83601.coverage similarity index 100% rename from tests/coverage/issue-83601.coverage rename to tests/coverage/iffy/issue-83601.coverage diff --git a/tests/coverage/issue-83601.rs b/tests/coverage/iffy/issue-83601.rs similarity index 100% rename from tests/coverage/issue-83601.rs rename to tests/coverage/iffy/issue-83601.rs diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/iffy/issue-84561.cov-map similarity index 100% rename from tests/coverage/issue-84561.cov-map rename to tests/coverage/iffy/issue-84561.cov-map diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/iffy/issue-84561.coverage similarity index 100% rename from tests/coverage/issue-84561.coverage rename to tests/coverage/iffy/issue-84561.coverage diff --git a/tests/coverage/issue-84561.rs b/tests/coverage/iffy/issue-84561.rs similarity index 100% rename from tests/coverage/issue-84561.rs rename to tests/coverage/iffy/issue-84561.rs diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/iffy/issue-85461.cov-map similarity index 100% rename from tests/coverage/issue-85461.cov-map rename to tests/coverage/iffy/issue-85461.cov-map diff --git a/tests/coverage/issue-85461.coverage b/tests/coverage/iffy/issue-85461.coverage similarity index 100% rename from tests/coverage/issue-85461.coverage rename to tests/coverage/iffy/issue-85461.coverage diff --git a/tests/coverage/issue-85461.rs b/tests/coverage/iffy/issue-85461.rs similarity index 100% rename from tests/coverage/issue-85461.rs rename to tests/coverage/iffy/issue-85461.rs diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/iffy/issue-93054.cov-map similarity index 100% rename from tests/coverage/issue-93054.cov-map rename to tests/coverage/iffy/issue-93054.cov-map diff --git a/tests/coverage/issue-93054.coverage b/tests/coverage/iffy/issue-93054.coverage similarity index 100% rename from tests/coverage/issue-93054.coverage rename to tests/coverage/iffy/issue-93054.coverage diff --git a/tests/coverage/issue-93054.rs b/tests/coverage/iffy/issue-93054.rs similarity index 100% rename from tests/coverage/issue-93054.rs rename to tests/coverage/iffy/issue-93054.rs diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/iffy/lazy_boolean.cov-map similarity index 100% rename from tests/coverage/lazy_boolean.cov-map rename to tests/coverage/iffy/lazy_boolean.cov-map diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/iffy/lazy_boolean.coverage similarity index 100% rename from tests/coverage/lazy_boolean.coverage rename to tests/coverage/iffy/lazy_boolean.coverage diff --git a/tests/coverage/lazy_boolean.rs b/tests/coverage/iffy/lazy_boolean.rs similarity index 100% rename from tests/coverage/lazy_boolean.rs rename to tests/coverage/iffy/lazy_boolean.rs diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/iffy/loops_branches.cov-map similarity index 100% rename from tests/coverage/loops_branches.cov-map rename to tests/coverage/iffy/loops_branches.cov-map diff --git a/tests/coverage/loops_branches.coverage b/tests/coverage/iffy/loops_branches.coverage similarity index 100% rename from tests/coverage/loops_branches.coverage rename to tests/coverage/iffy/loops_branches.coverage diff --git a/tests/coverage/loops_branches.rs b/tests/coverage/iffy/loops_branches.rs similarity index 100% rename from tests/coverage/loops_branches.rs rename to tests/coverage/iffy/loops_branches.rs diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/iffy/match_or_pattern.cov-map similarity index 100% rename from tests/coverage/match_or_pattern.cov-map rename to tests/coverage/iffy/match_or_pattern.cov-map diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/iffy/match_or_pattern.coverage similarity index 100% rename from tests/coverage/match_or_pattern.coverage rename to tests/coverage/iffy/match_or_pattern.coverage diff --git a/tests/coverage/match_or_pattern.rs b/tests/coverage/iffy/match_or_pattern.rs similarity index 100% rename from tests/coverage/match_or_pattern.rs rename to tests/coverage/iffy/match_or_pattern.rs diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/iffy/nested_loops.cov-map similarity index 100% rename from tests/coverage/nested_loops.cov-map rename to tests/coverage/iffy/nested_loops.cov-map diff --git a/tests/coverage/nested_loops.coverage b/tests/coverage/iffy/nested_loops.coverage similarity index 100% rename from tests/coverage/nested_loops.coverage rename to tests/coverage/iffy/nested_loops.coverage diff --git a/tests/coverage/nested_loops.rs b/tests/coverage/iffy/nested_loops.rs similarity index 100% rename from tests/coverage/nested_loops.rs rename to tests/coverage/iffy/nested_loops.rs diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/iffy/no_cov_crate.cov-map similarity index 100% rename from tests/coverage/no_cov_crate.cov-map rename to tests/coverage/iffy/no_cov_crate.cov-map diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/iffy/no_cov_crate.coverage similarity index 100% rename from tests/coverage/no_cov_crate.coverage rename to tests/coverage/iffy/no_cov_crate.coverage diff --git a/tests/coverage/no_cov_crate.rs b/tests/coverage/iffy/no_cov_crate.rs similarity index 100% rename from tests/coverage/no_cov_crate.rs rename to tests/coverage/iffy/no_cov_crate.rs diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/iffy/overflow.cov-map similarity index 100% rename from tests/coverage/overflow.cov-map rename to tests/coverage/iffy/overflow.cov-map diff --git a/tests/coverage/overflow.coverage b/tests/coverage/iffy/overflow.coverage similarity index 100% rename from tests/coverage/overflow.coverage rename to tests/coverage/iffy/overflow.coverage diff --git a/tests/coverage/overflow.rs b/tests/coverage/iffy/overflow.rs similarity index 100% rename from tests/coverage/overflow.rs rename to tests/coverage/iffy/overflow.rs diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/iffy/panic_unwind.cov-map similarity index 100% rename from tests/coverage/panic_unwind.cov-map rename to tests/coverage/iffy/panic_unwind.cov-map diff --git a/tests/coverage/panic_unwind.coverage b/tests/coverage/iffy/panic_unwind.coverage similarity index 100% rename from tests/coverage/panic_unwind.coverage rename to tests/coverage/iffy/panic_unwind.coverage diff --git a/tests/coverage/panic_unwind.rs b/tests/coverage/iffy/panic_unwind.rs similarity index 100% rename from tests/coverage/panic_unwind.rs rename to tests/coverage/iffy/panic_unwind.rs diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/iffy/partial_eq.cov-map similarity index 100% rename from tests/coverage/partial_eq.cov-map rename to tests/coverage/iffy/partial_eq.cov-map diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/iffy/partial_eq.coverage similarity index 100% rename from tests/coverage/partial_eq.coverage rename to tests/coverage/iffy/partial_eq.coverage diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/iffy/partial_eq.rs similarity index 100% rename from tests/coverage/partial_eq.rs rename to tests/coverage/iffy/partial_eq.rs diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/iffy/simple_loop.cov-map similarity index 100% rename from tests/coverage/simple_loop.cov-map rename to tests/coverage/iffy/simple_loop.cov-map diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/iffy/simple_loop.coverage similarity index 100% rename from tests/coverage/simple_loop.coverage rename to tests/coverage/iffy/simple_loop.coverage diff --git a/tests/coverage/simple_loop.rs b/tests/coverage/iffy/simple_loop.rs similarity index 100% rename from tests/coverage/simple_loop.rs rename to tests/coverage/iffy/simple_loop.rs diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/iffy/simple_match.cov-map similarity index 100% rename from tests/coverage/simple_match.cov-map rename to tests/coverage/iffy/simple_match.cov-map diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/iffy/simple_match.coverage similarity index 100% rename from tests/coverage/simple_match.coverage rename to tests/coverage/iffy/simple_match.coverage diff --git a/tests/coverage/simple_match.rs b/tests/coverage/iffy/simple_match.rs similarity index 100% rename from tests/coverage/simple_match.rs rename to tests/coverage/iffy/simple_match.rs diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/iffy/try_error_result.cov-map similarity index 100% rename from tests/coverage/try_error_result.cov-map rename to tests/coverage/iffy/try_error_result.cov-map diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/iffy/try_error_result.coverage similarity index 100% rename from tests/coverage/try_error_result.coverage rename to tests/coverage/iffy/try_error_result.coverage diff --git a/tests/coverage/try_error_result.rs b/tests/coverage/iffy/try_error_result.rs similarity index 100% rename from tests/coverage/try_error_result.rs rename to tests/coverage/iffy/try_error_result.rs diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/iffy/uses_crate.cov-map similarity index 100% rename from tests/coverage/uses_crate.cov-map rename to tests/coverage/iffy/uses_crate.cov-map diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/iffy/uses_crate.coverage similarity index 100% rename from tests/coverage/uses_crate.coverage rename to tests/coverage/iffy/uses_crate.coverage diff --git a/tests/coverage/uses_crate.rs b/tests/coverage/iffy/uses_crate.rs similarity index 100% rename from tests/coverage/uses_crate.rs rename to tests/coverage/iffy/uses_crate.rs diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/iffy/uses_inline_crate.cov-map similarity index 100% rename from tests/coverage/uses_inline_crate.cov-map rename to tests/coverage/iffy/uses_inline_crate.cov-map diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/iffy/uses_inline_crate.coverage similarity index 100% rename from tests/coverage/uses_inline_crate.coverage rename to tests/coverage/iffy/uses_inline_crate.coverage diff --git a/tests/coverage/uses_inline_crate.rs b/tests/coverage/iffy/uses_inline_crate.rs similarity index 100% rename from tests/coverage/uses_inline_crate.rs rename to tests/coverage/iffy/uses_inline_crate.rs diff --git a/tests/coverage/while.cov-map b/tests/coverage/iffy/while.cov-map similarity index 100% rename from tests/coverage/while.cov-map rename to tests/coverage/iffy/while.cov-map diff --git a/tests/coverage/while.coverage b/tests/coverage/iffy/while.coverage similarity index 100% rename from tests/coverage/while.coverage rename to tests/coverage/iffy/while.coverage diff --git a/tests/coverage/while.rs b/tests/coverage/iffy/while.rs similarity index 100% rename from tests/coverage/while.rs rename to tests/coverage/iffy/while.rs diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/iffy/while_early_ret.cov-map similarity index 100% rename from tests/coverage/while_early_ret.cov-map rename to tests/coverage/iffy/while_early_ret.cov-map diff --git a/tests/coverage/while_early_ret.coverage b/tests/coverage/iffy/while_early_ret.coverage similarity index 100% rename from tests/coverage/while_early_ret.coverage rename to tests/coverage/iffy/while_early_ret.coverage diff --git a/tests/coverage/while_early_ret.rs b/tests/coverage/iffy/while_early_ret.rs similarity index 100% rename from tests/coverage/while_early_ret.rs rename to tests/coverage/iffy/while_early_ret.rs diff --git a/tests/coverage/yield.cov-map b/tests/coverage/iffy/yield.cov-map similarity index 100% rename from tests/coverage/yield.cov-map rename to tests/coverage/iffy/yield.cov-map diff --git a/tests/coverage/yield.coverage b/tests/coverage/iffy/yield.coverage similarity index 100% rename from tests/coverage/yield.coverage rename to tests/coverage/iffy/yield.coverage diff --git a/tests/coverage/yield.rs b/tests/coverage/iffy/yield.rs similarity index 100% rename from tests/coverage/yield.rs rename to tests/coverage/iffy/yield.rs From 492fff70b80241545a29377b0480824a718d22a7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 2 Sep 2026 14:15:19 +1000 Subject: [PATCH 23/40] Add some simple coverage tests for common constructs --- tests/coverage/assert.cov-map | 72 +++++++++++++++++++++++ tests/coverage/assert.coverage | 42 +++++++++++++ tests/coverage/assert.rs | 41 +++++++++++++ tests/coverage/call-method.cov-map | 19 ++++++ tests/coverage/call-method.coverage | 46 +++++++++++++++ tests/coverage/call-method.rs | 45 ++++++++++++++ tests/coverage/for.many.coverage | 39 ++++++++++++ tests/coverage/for.one.coverage | 37 ++++++++++++ tests/coverage/for.rs | 36 ++++++++++++ tests/coverage/for.zero.cov-map | 30 ++++++++++ tests/coverage/for.zero.coverage | 39 ++++++++++++ tests/coverage/if-let-chain.none.cov-map | 40 +++++++++++++ tests/coverage/if-let-chain.none.coverage | 41 +++++++++++++ tests/coverage/if-let-chain.one.coverage | 41 +++++++++++++ tests/coverage/if-let-chain.rs | 38 ++++++++++++ tests/coverage/if-let-chain.two.coverage | 40 +++++++++++++ tests/coverage/if-tail-expr.no.cov-map | 45 ++++++++++++++ tests/coverage/if-tail-expr.no.coverage | 46 +++++++++++++++ tests/coverage/if-tail-expr.rs | 45 ++++++++++++++ tests/coverage/if-tail-expr.yes.coverage | 46 +++++++++++++++ tests/coverage/if-tail-stmt.no.cov-map | 34 +++++++++++ tests/coverage/if-tail-stmt.no.coverage | 46 +++++++++++++++ tests/coverage/if-tail-stmt.rs | 45 ++++++++++++++ tests/coverage/if-tail-stmt.yes.coverage | 48 +++++++++++++++ tests/coverage/let-else.none.cov-map | 38 ++++++++++++ tests/coverage/let-else.none.coverage | 39 ++++++++++++ tests/coverage/let-else.rs | 36 ++++++++++++ tests/coverage/let-else.some.coverage | 37 ++++++++++++ tests/coverage/match.cov-map | 49 +++++++++++++++ tests/coverage/match.coverage | 43 ++++++++++++++ tests/coverage/match.rs | 41 +++++++++++++ tests/coverage/while.cov-map | 42 +++++++++++++ tests/coverage/while.coverage | 34 +++++++++++ tests/coverage/while.rs | 33 +++++++++++ 34 files changed, 1393 insertions(+) create mode 100644 tests/coverage/assert.cov-map create mode 100644 tests/coverage/assert.coverage create mode 100644 tests/coverage/assert.rs create mode 100644 tests/coverage/call-method.cov-map create mode 100644 tests/coverage/call-method.coverage create mode 100644 tests/coverage/call-method.rs create mode 100644 tests/coverage/for.many.coverage create mode 100644 tests/coverage/for.one.coverage create mode 100644 tests/coverage/for.rs create mode 100644 tests/coverage/for.zero.cov-map create mode 100644 tests/coverage/for.zero.coverage create mode 100644 tests/coverage/if-let-chain.none.cov-map create mode 100644 tests/coverage/if-let-chain.none.coverage create mode 100644 tests/coverage/if-let-chain.one.coverage create mode 100644 tests/coverage/if-let-chain.rs create mode 100644 tests/coverage/if-let-chain.two.coverage create mode 100644 tests/coverage/if-tail-expr.no.cov-map create mode 100644 tests/coverage/if-tail-expr.no.coverage create mode 100644 tests/coverage/if-tail-expr.rs create mode 100644 tests/coverage/if-tail-expr.yes.coverage create mode 100644 tests/coverage/if-tail-stmt.no.cov-map create mode 100644 tests/coverage/if-tail-stmt.no.coverage create mode 100644 tests/coverage/if-tail-stmt.rs create mode 100644 tests/coverage/if-tail-stmt.yes.coverage create mode 100644 tests/coverage/let-else.none.cov-map create mode 100644 tests/coverage/let-else.none.coverage create mode 100644 tests/coverage/let-else.rs create mode 100644 tests/coverage/let-else.some.coverage create mode 100644 tests/coverage/match.cov-map create mode 100644 tests/coverage/match.coverage create mode 100644 tests/coverage/match.rs create mode 100644 tests/coverage/while.cov-map create mode 100644 tests/coverage/while.coverage create mode 100644 tests/coverage/while.rs diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map new file mode 100644 index 0000000000000..4500eab355739 --- /dev/null +++ b/tests/coverage/assert.cov-map @@ -0,0 +1,72 @@ +Function name: assert::assert_a_plain +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 06, 01, 00, 25, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 10, 01, 00, 11, 00, 18, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 15, 01, 05, 00, 14, 0d, 00, 15, 00, 18, 11, 00, 1f, 00, 25, 15, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/assert.rs +Number of expressions: 0 +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(5)) at (prev + 1, 5) to (start + 0, 20) +- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(5)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c5 + +Function name: assert::assert_b_message +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 0d, 01, 00, 27, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 10, 01, 00, 11, 00, 18, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 15, 01, 05, 00, 14, 0d, 00, 15, 00, 18, 11, 00, 1f, 00, 25, 15, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/assert.rs +Number of expressions: 0 +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 39) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(5)) at (prev + 1, 5) to (start + 0, 20) +- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(5)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c5 + +Function name: assert::assert_c_format_inline +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 14, 01, 00, 38, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 10, 01, 00, 11, 00, 18, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 15, 01, 05, 00, 14, 0d, 00, 15, 00, 18, 11, 00, 1f, 00, 25, 15, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/assert.rs +Number of expressions: 0 +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 20, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(5)) at (prev + 1, 5) to (start + 0, 20) +- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(5)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c5 + +Function name: assert::assert_d_format_arg +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 1b, 01, 00, 35, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 10, 01, 00, 11, 00, 18, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 15, 01, 05, 00, 14, 0d, 00, 15, 00, 18, 11, 00, 1f, 00, 25, 15, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/assert.rs +Number of expressions: 0 +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 53) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(5)) at (prev + 1, 5) to (start + 0, 20) +- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(5)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c5 + diff --git a/tests/coverage/assert.coverage b/tests/coverage/assert.coverage new file mode 100644 index 0000000000000..d9171fd705c99 --- /dev/null +++ b/tests/coverage/assert.coverage @@ -0,0 +1,42 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| | + LL| |use core::assert_matches; + LL| | + LL| 1|fn assert_a_plain(opt: Option<&str>) { + LL| 1| assert!(opt.is_some()); + LL| 1| assert_eq!(opt, Some("true")); + LL| 1| assert_ne!(opt, None); + LL| 1| assert_matches!(opt, Some("true")); + LL| 1|} + LL| | + LL| 1|fn assert_b_message(opt: Option<&str>) { + LL| 1| assert!(opt.is_some(), "message"); + LL| 1| assert_eq!(opt, Some("true"), "message"); + LL| 1| assert_ne!(opt, None, "message"); + LL| 1| assert_matches!(opt, Some("true"), "message"); + LL| 1|} + LL| | + LL| 1|fn assert_c_format_inline(opt: Option<&str>, msg: &str) { + LL| 1| assert!(opt.is_some(), "message: {msg}"); + LL| 1| assert_eq!(opt, Some("true"), "message: {msg}"); + LL| 1| assert_ne!(opt, None, "message: {msg}"); + LL| 1| assert_matches!(opt, Some("true"), "message: {msg}"); + LL| 1|} + LL| | + LL| 1|fn assert_d_format_arg(opt: Option<&str>, msg: &str) { + LL| 1| assert!(opt.is_some(), "message: {}", msg); + LL| 1| assert_eq!(opt, Some("true"), "message: {}", msg); + LL| 1| assert_ne!(opt, None, "message: {}", msg); + LL| 1| assert_matches!(opt, Some("true"), "message: {}", msg); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt = core::hint::black_box(Some("true")); + LL| | assert_a_plain(opt); + LL| | assert_b_message(opt); + LL| | assert_c_format_inline(opt, "message"); + LL| | assert_d_format_arg(opt, "message"); + LL| |} + diff --git a/tests/coverage/assert.rs b/tests/coverage/assert.rs new file mode 100644 index 0000000000000..9c3151ba4ce17 --- /dev/null +++ b/tests/coverage/assert.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 + +use core::assert_matches; + +fn assert_a_plain(opt: Option<&str>) { + assert!(opt.is_some()); + assert_eq!(opt, Some("true")); + assert_ne!(opt, None); + assert_matches!(opt, Some("true")); +} + +fn assert_b_message(opt: Option<&str>) { + assert!(opt.is_some(), "message"); + assert_eq!(opt, Some("true"), "message"); + assert_ne!(opt, None, "message"); + assert_matches!(opt, Some("true"), "message"); +} + +fn assert_c_format_inline(opt: Option<&str>, msg: &str) { + assert!(opt.is_some(), "message: {msg}"); + assert_eq!(opt, Some("true"), "message: {msg}"); + assert_ne!(opt, None, "message: {msg}"); + assert_matches!(opt, Some("true"), "message: {msg}"); +} + +fn assert_d_format_arg(opt: Option<&str>, msg: &str) { + assert!(opt.is_some(), "message: {}", msg); + assert_eq!(opt, Some("true"), "message: {}", msg); + assert_ne!(opt, None, "message: {}", msg); + assert_matches!(opt, Some("true"), "message: {}", msg); +} + +#[coverage(off)] +fn main() { + let opt = core::hint::black_box(Some("true")); + assert_a_plain(opt); + assert_b_message(opt); + assert_c_format_inline(opt, "message"); + assert_d_format_arg(opt, "message"); +} diff --git a/tests/coverage/call-method.cov-map b/tests/coverage/call-method.cov-map new file mode 100644 index 0000000000000..534cc4b6a58af --- /dev/null +++ b/tests/coverage/call-method.cov-map @@ -0,0 +1,19 @@ +Function name: call_method::call_method +Raw bytes (59): 0x[01, 01, 00, 0b, 01, 08, 01, 00, 11, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 16, 01, 02, 05, 00, 0a, 01, 02, 09, 00, 0f, 01, 02, 0d, 00, 12, 01, 04, 05, 05, 0a, 01, 00, 05, 00, 0a, 01, 07, 09, 00, 0f, 01, 02, 0d, 00, 12, 01, 03, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/call-method.rs +Number of expressions: 0 +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 4, 5) to (start + 5, 10) +- Code(Counter(0)) at (prev + 0, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 7, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c0 + diff --git a/tests/coverage/call-method.coverage b/tests/coverage/call-method.coverage new file mode 100644 index 0000000000000..afcdb0adc7b73 --- /dev/null +++ b/tests/coverage/call-method.coverage @@ -0,0 +1,46 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ min-llvm-version: 23 + LL| | + LL| |// Basic test for method calls and chained method calls. + LL| | + LL| |#[rustfmt::skip] + LL| 1|fn call_method() { + LL| 1| let thing = Thing; + LL| | + LL| 1| thing + LL| | . + LL| 1| method + LL| | ( + LL| 1| "arg" + LL| | ) + LL| | ; + LL| | + LL| 1| thing + LL| 1| . + LL| 1| method + LL| 1| ( + LL| 1| "arg" + LL| 1| ) + LL| | . + LL| 1| method + LL| | ( + LL| 1| "arg" + LL| | ) + LL| | ; + LL| 1|} + LL| | + LL| |struct Thing; + LL| | + LL| |#[coverage(off)] + LL| |impl Thing { + LL| | fn method(&self, _arg: &str) -> &Self { + LL| | self + LL| | } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | call_method(); + LL| |} + diff --git a/tests/coverage/call-method.rs b/tests/coverage/call-method.rs new file mode 100644 index 0000000000000..42b753503331b --- /dev/null +++ b/tests/coverage/call-method.rs @@ -0,0 +1,45 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ min-llvm-version: 23 + +// Basic test for method calls and chained method calls. + +#[rustfmt::skip] +fn call_method() { + let thing = Thing; + + thing + . + method + ( + "arg" + ) + ; + + thing + . + method + ( + "arg" + ) + . + method + ( + "arg" + ) + ; +} + +struct Thing; + +#[coverage(off)] +impl Thing { + fn method(&self, _arg: &str) -> &Self { + self + } +} + +#[coverage(off)] +fn main() { + call_method(); +} diff --git a/tests/coverage/for.many.coverage b/tests/coverage/for.many.coverage new file mode 100644 index 0000000000000..c6908b64cd615 --- /dev/null +++ b/tests/coverage/for.many.coverage @@ -0,0 +1,39 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: zero one many + LL| |//@[one] ignore-coverage-map + LL| |//@[many] ignore-coverage-map + LL| | + LL| |// Basic test of `for` loops. + LL| | + LL| 1|fn for_loop(items: &[&str]) { + LL| 1| say("hello"); + LL| | + LL| 3| for item in items { + ^1 + LL| 3| say(item); + LL| 3| } + LL| | + LL| 3| for item in items { + ^1 + LL| 3| say(item) + LL| | } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let items = cfg_select!( + LL| | zero => &[], + LL| | one => &["one"], + LL| | many => &["one", "two", "three"], + LL| | ); + LL| | for_loop(items); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/for.one.coverage b/tests/coverage/for.one.coverage new file mode 100644 index 0000000000000..285d379c526f9 --- /dev/null +++ b/tests/coverage/for.one.coverage @@ -0,0 +1,37 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: zero one many + LL| |//@[one] ignore-coverage-map + LL| |//@[many] ignore-coverage-map + LL| | + LL| |// Basic test of `for` loops. + LL| | + LL| 1|fn for_loop(items: &[&str]) { + LL| 1| say("hello"); + LL| | + LL| 1| for item in items { + LL| 1| say(item); + LL| 1| } + LL| | + LL| 1| for item in items { + LL| 1| say(item) + LL| | } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let items = cfg_select!( + LL| | zero => &[], + LL| | one => &["one"], + LL| | many => &["one", "two", "three"], + LL| | ); + LL| | for_loop(items); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/for.rs b/tests/coverage/for.rs new file mode 100644 index 0000000000000..55a2cfc2c18d2 --- /dev/null +++ b/tests/coverage/for.rs @@ -0,0 +1,36 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ revisions: zero one many +//@[one] ignore-coverage-map +//@[many] ignore-coverage-map + +// Basic test of `for` loops. + +fn for_loop(items: &[&str]) { + say("hello"); + + for item in items { + say(item); + } + + for item in items { + say(item) + } + + say("goodbye"); +} + +#[coverage(off)] +fn main() { + let items = cfg_select!( + zero => &[], + one => &["one"], + many => &["one", "two", "three"], + ); + for_loop(items); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/for.zero.cov-map b/tests/coverage/for.zero.cov-map new file mode 100644 index 0000000000000..4ac461b85719f --- /dev/null +++ b/tests/coverage/for.zero.cov-map @@ -0,0 +1,30 @@ +Function name: for::for_loop +Raw bytes (77): 0x[01, 01, 04, 05, 01, 09, 01, 09, 01, 09, 01, 0d, 01, 09, 01, 00, 1c, 01, 01, 05, 00, 08, 01, 00, 09, 00, 10, 02, 02, 09, 00, 0d, 01, 00, 11, 00, 16, 02, 00, 17, 02, 06, 0e, 04, 09, 00, 0d, 01, 00, 11, 00, 16, 0e, 01, 09, 00, 0c, 0e, 00, 0d, 00, 11, 01, 03, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/for.rs +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Counter(0) +- expression 1 operands: lhs = Counter(2), rhs = Counter(0) +- expression 2 operands: lhs = Counter(2), rhs = Counter(0) +- expression 3 operands: lhs = Counter(2), rhs = Counter(0) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 13) + = (c1 - c0) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 2, 6) + = (c1 - c0) +- Code(Expression(3, Sub)) at (prev + 4, 9) to (start + 0, 13) + = (c2 - c0) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Expression(3, Sub)) at (prev + 1, 9) to (start + 0, 12) + = (c2 - c0) +- Code(Expression(3, Sub)) at (prev + 0, 13) to (start + 0, 17) + = (c2 - c0) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + diff --git a/tests/coverage/for.zero.coverage b/tests/coverage/for.zero.coverage new file mode 100644 index 0000000000000..9376a371275d4 --- /dev/null +++ b/tests/coverage/for.zero.coverage @@ -0,0 +1,39 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: zero one many + LL| |//@[one] ignore-coverage-map + LL| |//@[many] ignore-coverage-map + LL| | + LL| |// Basic test of `for` loops. + LL| | + LL| 1|fn for_loop(items: &[&str]) { + LL| 1| say("hello"); + LL| | + LL| 1| for item in items { + ^0 + LL| 0| say(item); + LL| 0| } + LL| | + LL| 1| for item in items { + ^0 + LL| 0| say(item) + LL| | } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let items = cfg_select!( + LL| | zero => &[], + LL| | one => &["one"], + LL| | many => &["one", "two", "three"], + LL| | ); + LL| | for_loop(items); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-let-chain.none.cov-map b/tests/coverage/if-let-chain.none.cov-map new file mode 100644 index 0000000000000..9626b6cc8553b --- /dev/null +++ b/tests/coverage/if-let-chain.none.cov-map @@ -0,0 +1,40 @@ +Function name: if_let_chain::if_let_chain +Raw bytes (105): 0x[01, 01, 08, 09, 05, 0b, 09, 01, 05, 11, 0d, 11, 0d, 11, 0d, 1f, 11, 01, 0d, 11, 01, 09, 01, 00, 33, 09, 01, 11, 00, 18, 01, 00, 1c, 00, 27, 02, 01, 15, 00, 18, 09, 00, 1c, 00, 23, 02, 01, 05, 02, 06, 06, 02, 05, 00, 06, 11, 02, 11, 00, 18, 01, 00, 1c, 00, 27, 16, 01, 15, 00, 18, 11, 00, 1c, 00, 23, 16, 02, 09, 00, 0c, 16, 00, 0d, 00, 10, 1a, 01, 05, 00, 06, 01, 02, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/if-let-chain.rs +Number of expressions: 8 +- expression 0 operands: lhs = Counter(2), rhs = Counter(1) +- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(4), rhs = Counter(3) +- expression 4 operands: lhs = Counter(4), rhs = Counter(3) +- expression 5 operands: lhs = Counter(4), rhs = Counter(3) +- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4) +- expression 7 operands: lhs = Counter(0), rhs = Counter(3) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 51) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 39) +- Code(Expression(0, Sub)) at (prev + 1, 21) to (start + 0, 24) + = (c2 - c1) +- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 35) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 2, 6) + = (c2 - c1) +- Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) + = ((c0 + c1) - c2) +- Code(Counter(4)) at (prev + 2, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 39) +- Code(Expression(5, Sub)) at (prev + 1, 21) to (start + 0, 24) + = (c4 - c3) +- Code(Counter(4)) at (prev + 0, 28) to (start + 0, 35) +- Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 0, 12) + = (c4 - c3) +- Code(Expression(5, Sub)) at (prev + 0, 13) to (start + 0, 16) + = (c4 - c3) +- Code(Expression(6, Sub)) at (prev + 1, 5) to (start + 0, 6) + = ((c0 + c3) - c4) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 + diff --git a/tests/coverage/if-let-chain.none.coverage b/tests/coverage/if-let-chain.none.coverage new file mode 100644 index 0000000000000..a5aba75201ead --- /dev/null +++ b/tests/coverage/if-let-chain.none.coverage @@ -0,0 +1,41 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: none one two + LL| |//@[one] ignore-coverage-map + LL| |//@[two] ignore-coverage-map + LL| | + LL| |// Basic test for if-let chains. + LL| | + LL| 1|fn if_let_chain(opt_opt_msg: Option>) { + LL| 1| if let Some(opt_msg) = opt_opt_msg + ^0 + LL| 0| && let Some(msg) = opt_msg + LL| 0| { + LL| 0| say(msg); + LL| 1| } + LL| | + LL| 1| if let Some(opt_msg) = opt_opt_msg + ^0 + LL| 0| && let Some(msg) = opt_msg + LL| | { + LL| 0| say(msg) + LL| 1| } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt_opt_msg = cfg_select!( + LL| | none => None, + LL| | one => Some(None), + LL| | two => Some(Some("hello")), + LL| | ); + LL| | if_let_chain(opt_opt_msg); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-let-chain.one.coverage b/tests/coverage/if-let-chain.one.coverage new file mode 100644 index 0000000000000..b4789e8593af6 --- /dev/null +++ b/tests/coverage/if-let-chain.one.coverage @@ -0,0 +1,41 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: none one two + LL| |//@[one] ignore-coverage-map + LL| |//@[two] ignore-coverage-map + LL| | + LL| |// Basic test for if-let chains. + LL| | + LL| 1|fn if_let_chain(opt_opt_msg: Option>) { + LL| 1| if let Some(opt_msg) = opt_opt_msg + LL| 1| && let Some(msg) = opt_msg + ^0 + LL| 0| { + LL| 0| say(msg); + LL| 1| } + LL| | + LL| 1| if let Some(opt_msg) = opt_opt_msg + LL| 1| && let Some(msg) = opt_msg + ^0 + LL| | { + LL| 0| say(msg) + LL| 1| } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt_opt_msg = cfg_select!( + LL| | none => None, + LL| | one => Some(None), + LL| | two => Some(Some("hello")), + LL| | ); + LL| | if_let_chain(opt_opt_msg); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-let-chain.rs b/tests/coverage/if-let-chain.rs new file mode 100644 index 0000000000000..816a22015a4c7 --- /dev/null +++ b/tests/coverage/if-let-chain.rs @@ -0,0 +1,38 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ revisions: none one two +//@[one] ignore-coverage-map +//@[two] ignore-coverage-map + +// Basic test for if-let chains. + +fn if_let_chain(opt_opt_msg: Option>) { + if let Some(opt_msg) = opt_opt_msg + && let Some(msg) = opt_msg + { + say(msg); + } + + if let Some(opt_msg) = opt_opt_msg + && let Some(msg) = opt_msg + { + say(msg) + } + + say("goodbye"); +} + +#[coverage(off)] +fn main() { + let opt_opt_msg = cfg_select!( + none => None, + one => Some(None), + two => Some(Some("hello")), + ); + if_let_chain(opt_opt_msg); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/if-let-chain.two.coverage b/tests/coverage/if-let-chain.two.coverage new file mode 100644 index 0000000000000..491a704da1289 --- /dev/null +++ b/tests/coverage/if-let-chain.two.coverage @@ -0,0 +1,40 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: none one two + LL| |//@[one] ignore-coverage-map + LL| |//@[two] ignore-coverage-map + LL| | + LL| |// Basic test for if-let chains. + LL| | + LL| 1|fn if_let_chain(opt_opt_msg: Option>) { + LL| 1| if let Some(opt_msg) = opt_opt_msg + LL| 1| && let Some(msg) = opt_msg + LL| 1| { + LL| 1| say(msg); + LL| 1| } + ^0 + LL| | + LL| 1| if let Some(opt_msg) = opt_opt_msg + LL| 1| && let Some(msg) = opt_msg + LL| | { + LL| 1| say(msg) + LL| 0| } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt_opt_msg = cfg_select!( + LL| | none => None, + LL| | one => Some(None), + LL| | two => Some(Some("hello")), + LL| | ); + LL| | if_let_chain(opt_opt_msg); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-tail-expr.no.cov-map b/tests/coverage/if-tail-expr.no.cov-map new file mode 100644 index 0000000000000..3849ec62daae8 --- /dev/null +++ b/tests/coverage/if-tail-expr.no.cov-map @@ -0,0 +1,45 @@ +Function name: if_tail_expr::if_true +Raw bytes (135): 0x[01, 01, 08, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 1f, 0d, 11, 01, 1f, 0d, 11, 17, 01, 09, 01, 00, 24, 01, 01, 05, 00, 08, 01, 00, 09, 00, 10, 01, 02, 08, 00, 0c, 05, 01, 09, 00, 0c, 05, 00, 0d, 00, 13, 02, 01, 05, 00, 06, 01, 02, 08, 00, 0c, 09, 01, 09, 00, 0c, 09, 00, 0d, 00, 13, 0a, 02, 09, 00, 0c, 0a, 00, 0d, 00, 14, 01, 03, 08, 00, 0c, 0d, 01, 09, 00, 0c, 0d, 00, 0d, 00, 13, 0e, 01, 0f, 00, 14, 11, 01, 09, 00, 0c, 11, 00, 0d, 00, 14, 1a, 02, 09, 00, 0c, 1a, 00, 0d, 00, 16, 01, 03, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/if-tail-expr.rs +Number of expressions: 8 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) +- expression 3 operands: lhs = Counter(0), rhs = Counter(3) +- expression 4 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +- expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(3), rhs = Counter(4) +Number of file 0 mappings: 23 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) + = (c0 - c1) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(2)) at (prev + 0, 13) to (start + 0, 19) +- Code(Expression(2, Sub)) at (prev + 2, 9) to (start + 0, 12) + = (c0 - c2) +- Code(Expression(2, Sub)) at (prev + 0, 13) to (start + 0, 20) + = (c0 - c2) +- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 12) +- Code(Counter(3)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(3)) at (prev + 0, 13) to (start + 0, 19) +- Code(Expression(3, Sub)) at (prev + 1, 15) to (start + 0, 20) + = (c0 - c3) +- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(4)) at (prev + 0, 13) to (start + 0, 20) +- Code(Expression(6, Sub)) at (prev + 2, 9) to (start + 0, 12) + = (c0 - (c3 + c4)) +- Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 0, 22) + = (c0 - (c3 + c4)) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 + diff --git a/tests/coverage/if-tail-expr.no.coverage b/tests/coverage/if-tail-expr.no.coverage new file mode 100644 index 0000000000000..a33a58a6c30e6 --- /dev/null +++ b/tests/coverage/if-tail-expr.no.coverage @@ -0,0 +1,46 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: no yes + LL| |//@[yes] ignore-coverage-map + LL| | + LL| |// A variety of simple `if` expressions, in which the then/else blocks end with + LL| |// an expression. Contrast with `if-tail-stmt.rs`. + LL| | + LL| 1|fn if_true(cond: bool, other: bool) { + LL| 1| say("hello"); + LL| | + LL| 1| if cond { + LL| 0| say("true") + LL| 1| } + LL| | + LL| 1| if cond { + LL| 0| say("true") + LL| | } else { + LL| 1| say("false") + LL| | } + LL| | + LL| 1| if cond { + LL| 0| say("cond") + LL| 1| } else if other { + LL| 1| say("other") + LL| | } else { + LL| 0| say("neither") + LL| | } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let cond = cfg_select!( + LL| | no => false, + LL| | yes => true, + LL| | ); + LL| | if_true(cond, !cond); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-tail-expr.rs b/tests/coverage/if-tail-expr.rs new file mode 100644 index 0000000000000..778a9ecc8380c --- /dev/null +++ b/tests/coverage/if-tail-expr.rs @@ -0,0 +1,45 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ revisions: no yes +//@[yes] ignore-coverage-map + +// A variety of simple `if` expressions, in which the then/else blocks end with +// an expression. Contrast with `if-tail-stmt.rs`. + +fn if_true(cond: bool, other: bool) { + say("hello"); + + if cond { + say("true") + } + + if cond { + say("true") + } else { + say("false") + } + + if cond { + say("cond") + } else if other { + say("other") + } else { + say("neither") + } + + say("goodbye"); +} + +#[coverage(off)] +fn main() { + let cond = cfg_select!( + no => false, + yes => true, + ); + if_true(cond, !cond); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/if-tail-expr.yes.coverage b/tests/coverage/if-tail-expr.yes.coverage new file mode 100644 index 0000000000000..111efccf59b15 --- /dev/null +++ b/tests/coverage/if-tail-expr.yes.coverage @@ -0,0 +1,46 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: no yes + LL| |//@[yes] ignore-coverage-map + LL| | + LL| |// A variety of simple `if` expressions, in which the then/else blocks end with + LL| |// an expression. Contrast with `if-tail-stmt.rs`. + LL| | + LL| 1|fn if_true(cond: bool, other: bool) { + LL| 1| say("hello"); + LL| | + LL| 1| if cond { + LL| 1| say("true") + LL| 0| } + LL| | + LL| 1| if cond { + LL| 1| say("true") + LL| | } else { + LL| 0| say("false") + LL| | } + LL| | + LL| 1| if cond { + LL| 1| say("cond") + LL| 0| } else if other { + LL| 0| say("other") + LL| | } else { + LL| 0| say("neither") + LL| | } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let cond = cfg_select!( + LL| | no => false, + LL| | yes => true, + LL| | ); + LL| | if_true(cond, !cond); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-tail-stmt.no.cov-map b/tests/coverage/if-tail-stmt.no.cov-map new file mode 100644 index 0000000000000..e5721e2dc4a74 --- /dev/null +++ b/tests/coverage/if-tail-stmt.no.cov-map @@ -0,0 +1,34 @@ +Function name: if_tail_stmt::if_true +Raw bytes (99): 0x[01, 01, 05, 01, 05, 01, 09, 01, 0d, 01, 13, 0d, 11, 11, 01, 09, 01, 00, 24, 01, 01, 05, 00, 08, 01, 00, 09, 00, 10, 01, 02, 08, 00, 0c, 05, 00, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 02, 08, 00, 0c, 09, 00, 0d, 02, 06, 06, 02, 0c, 02, 06, 01, 04, 08, 00, 0c, 0d, 00, 0d, 02, 06, 0a, 02, 0f, 00, 14, 11, 00, 15, 02, 06, 0e, 02, 0c, 02, 06, 01, 04, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/if-tail-stmt.rs +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(3) +- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(3), rhs = Counter(4) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) + = (c0 - c1) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(2)) at (prev + 0, 13) to (start + 2, 6) +- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c2) +- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 12) +- Code(Counter(3)) at (prev + 0, 13) to (start + 2, 6) +- Code(Expression(2, Sub)) at (prev + 2, 15) to (start + 0, 20) + = (c0 - c3) +- Code(Counter(4)) at (prev + 0, 21) to (start + 2, 6) +- Code(Expression(3, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - (c3 + c4)) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 + diff --git a/tests/coverage/if-tail-stmt.no.coverage b/tests/coverage/if-tail-stmt.no.coverage new file mode 100644 index 0000000000000..ca311f21ff229 --- /dev/null +++ b/tests/coverage/if-tail-stmt.no.coverage @@ -0,0 +1,46 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: no yes + LL| |//@[yes] ignore-coverage-map + LL| | + LL| |// A variety of simple `if` expressions, in which the then/else blocks end with + LL| |// a semicolon. Contrast with `if-tail-expr.rs`. + LL| | + LL| 1|fn if_true(cond: bool, other: bool) { + LL| 1| say("hello"); + LL| | + LL| 1| if cond { + LL| 0| say("true"); + LL| 1| } + LL| | + LL| 1| if cond { + LL| 0| say("true"); + LL| 1| } else { + LL| 1| say("false"); + LL| 1| } + LL| | + LL| 1| if cond { + LL| 0| say("cond"); + LL| 1| } else if other { + LL| 1| say("other"); + LL| 1| } else { + LL| 0| say("neither"); + LL| 0| } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let cond = cfg_select!( + LL| | no => false, + LL| | yes => true, + LL| | ); + LL| | if_true(cond, !cond); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/if-tail-stmt.rs b/tests/coverage/if-tail-stmt.rs new file mode 100644 index 0000000000000..f350c4eba90b0 --- /dev/null +++ b/tests/coverage/if-tail-stmt.rs @@ -0,0 +1,45 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ revisions: no yes +//@[yes] ignore-coverage-map + +// A variety of simple `if` expressions, in which the then/else blocks end with +// a semicolon. Contrast with `if-tail-expr.rs`. + +fn if_true(cond: bool, other: bool) { + say("hello"); + + if cond { + say("true"); + } + + if cond { + say("true"); + } else { + say("false"); + } + + if cond { + say("cond"); + } else if other { + say("other"); + } else { + say("neither"); + } + + say("goodbye"); +} + +#[coverage(off)] +fn main() { + let cond = cfg_select!( + no => false, + yes => true, + ); + if_true(cond, !cond); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/if-tail-stmt.yes.coverage b/tests/coverage/if-tail-stmt.yes.coverage new file mode 100644 index 0000000000000..b4fa1884315e6 --- /dev/null +++ b/tests/coverage/if-tail-stmt.yes.coverage @@ -0,0 +1,48 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: no yes + LL| |//@[yes] ignore-coverage-map + LL| | + LL| |// A variety of simple `if` expressions, in which the then/else blocks end with + LL| |// a semicolon. Contrast with `if-tail-expr.rs`. + LL| | + LL| 1|fn if_true(cond: bool, other: bool) { + LL| 1| say("hello"); + LL| | + LL| 1| if cond { + LL| 1| say("true"); + LL| 1| } + ^0 + LL| | + LL| 1| if cond { + LL| 1| say("true"); + LL| 1| } else { + LL| 0| say("false"); + LL| 0| } + LL| | + LL| 1| if cond { + LL| 1| say("cond"); + LL| 1| } else if other { + ^0 + LL| 0| say("other"); + LL| 0| } else { + LL| 0| say("neither"); + LL| 0| } + LL| | + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let cond = cfg_select!( + LL| | no => false, + LL| | yes => true, + LL| | ); + LL| | if_true(cond, !cond); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/let-else.none.cov-map b/tests/coverage/let-else.none.cov-map new file mode 100644 index 0000000000000..af5b34cb36f79 --- /dev/null +++ b/tests/coverage/let-else.none.cov-map @@ -0,0 +1,38 @@ +Function name: let_else::let_else_no_semi +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 10, 01, 00, 2b, 02, 01, 0e, 00, 11, 01, 00, 15, 00, 1c, 05, 01, 09, 00, 0f, 02, 02, 05, 00, 08, 02, 00, 09, 00, 0c, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/let-else.rs +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 43) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 17) + = (c0 - c1) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 28) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 8) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 0, 9) to (start + 0, 12) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 + +Function name: let_else::let_else_semi +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 08, 01, 00, 28, 02, 01, 0e, 00, 11, 01, 00, 15, 00, 1c, 05, 01, 09, 00, 0f, 02, 02, 05, 00, 08, 02, 00, 09, 00, 0c, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/let-else.rs +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 40) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 17) + = (c0 - c1) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 28) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 8) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 0, 9) to (start + 0, 12) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 + diff --git a/tests/coverage/let-else.none.coverage b/tests/coverage/let-else.none.coverage new file mode 100644 index 0000000000000..a24877eb90a03 --- /dev/null +++ b/tests/coverage/let-else.none.coverage @@ -0,0 +1,39 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: none some + LL| |//@[some] ignore-coverage-map + LL| | + LL| |// Basic test for let-else statements. + LL| | + LL| 1|fn let_else_semi(opt_msg: Option<&str>) { + LL| 1| let Some(msg) = opt_msg else { + ^0 + LL| 1| return; + LL| | }; + LL| 0| say(msg); + LL| 1|} + LL| | + LL| |#[rustfmt::skip] + LL| 1|fn let_else_no_semi(opt_msg: Option<&str>) { + LL| 1| let Some(msg) = opt_msg else { + ^0 + LL| 1| return + LL| | }; + LL| 0| say(msg); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt_msg = cfg_select!( + LL| | some => Some("hello"), + LL| | none => None, + LL| | ); + LL| | let_else_semi(opt_msg); + LL| | let_else_no_semi(opt_msg); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/let-else.rs b/tests/coverage/let-else.rs new file mode 100644 index 0000000000000..0ebef52d649c7 --- /dev/null +++ b/tests/coverage/let-else.rs @@ -0,0 +1,36 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 +//@ revisions: none some +//@[some] ignore-coverage-map + +// Basic test for let-else statements. + +fn let_else_semi(opt_msg: Option<&str>) { + let Some(msg) = opt_msg else { + return; + }; + say(msg); +} + +#[rustfmt::skip] +fn let_else_no_semi(opt_msg: Option<&str>) { + let Some(msg) = opt_msg else { + return + }; + say(msg); +} + +#[coverage(off)] +fn main() { + let opt_msg = cfg_select!( + some => Some("hello"), + none => None, + ); + let_else_semi(opt_msg); + let_else_no_semi(opt_msg); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/let-else.some.coverage b/tests/coverage/let-else.some.coverage new file mode 100644 index 0000000000000..828731b199f95 --- /dev/null +++ b/tests/coverage/let-else.some.coverage @@ -0,0 +1,37 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| |//@ revisions: none some + LL| |//@[some] ignore-coverage-map + LL| | + LL| |// Basic test for let-else statements. + LL| | + LL| 1|fn let_else_semi(opt_msg: Option<&str>) { + LL| 1| let Some(msg) = opt_msg else { + LL| 0| return; + LL| | }; + LL| 1| say(msg); + LL| 1|} + LL| | + LL| |#[rustfmt::skip] + LL| 1|fn let_else_no_semi(opt_msg: Option<&str>) { + LL| 1| let Some(msg) = opt_msg else { + LL| 0| return + LL| | }; + LL| 1| say(msg); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | let opt_msg = cfg_select!( + LL| | some => Some("hello"), + LL| | none => None, + LL| | ); + LL| | let_else_semi(opt_msg); + LL| | let_else_no_semi(opt_msg); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/match.cov-map b/tests/coverage/match.cov-map new file mode 100644 index 0000000000000..ac9433fda2dcb --- /dev/null +++ b/tests/coverage/match.cov-map @@ -0,0 +1,49 @@ +Function name: match::match_expr +Raw bytes (131): 0x[01, 01, 0b, 1d, 07, 0b, 19, 0f, 15, 05, 0d, 0d, 11, 0d, 11, 05, 09, 05, 09, 05, 09, 01, 1d, 01, 1d, 15, 01, 06, 01, 00, 2a, 0d, 01, 0b, 00, 0c, 02, 01, 14, 00, 17, 02, 00, 18, 00, 1e, 19, 03, 0d, 00, 10, 19, 00, 11, 00, 16, 15, 02, 14, 02, 0a, 11, 03, 17, 00, 18, 11, 00, 1c, 02, 0a, 16, 03, 14, 00, 17, 16, 00, 18, 00, 1f, 09, 01, 0e, 00, 13, 05, 00, 18, 00, 1d, 09, 00, 21, 00, 22, 09, 00, 26, 02, 0a, 22, 03, 0e, 00, 13, 22, 00, 18, 00, 1b, 22, 00, 1c, 00, 23, 2a, 01, 11, 00, 14, 2a, 00, 15, 00, 1b, 01, 02, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/match.rs +Number of expressions: 11 +- expression 0 operands: lhs = Counter(7), rhs = Expression(1, Add) +- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(6) +- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) +- expression 3 operands: lhs = Counter(1), rhs = Counter(3) +- expression 4 operands: lhs = Counter(3), rhs = Counter(4) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +- expression 6 operands: lhs = Counter(1), rhs = Counter(2) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +- expression 9 operands: lhs = Counter(0), rhs = Counter(7) +- expression 10 operands: lhs = Counter(0), rhs = Counter(7) +Number of file 0 mappings: 21 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 42) +- Code(Counter(3)) at (prev + 1, 11) to (start + 0, 12) +- Code(Expression(0, Sub)) at (prev + 1, 20) to (start + 0, 23) + = (c7 - (((c1 + c3) + c5) + c6)) +- Code(Expression(0, Sub)) at (prev + 0, 24) to (start + 0, 30) + = (c7 - (((c1 + c3) + c5) + c6)) +- Code(Counter(6)) at (prev + 3, 13) to (start + 0, 16) +- Code(Counter(6)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(5)) at (prev + 2, 20) to (start + 2, 10) +- Code(Counter(4)) at (prev + 3, 23) to (start + 0, 24) +- Code(Counter(4)) at (prev + 0, 28) to (start + 2, 10) +- Code(Expression(5, Sub)) at (prev + 3, 20) to (start + 0, 23) + = (c3 - c4) +- Code(Expression(5, Sub)) at (prev + 0, 24) to (start + 0, 31) + = (c3 - c4) +- Code(Counter(2)) at (prev + 1, 14) to (start + 0, 19) +- Code(Counter(1)) at (prev + 0, 24) to (start + 0, 29) +- Code(Counter(2)) at (prev + 0, 33) to (start + 0, 34) +- Code(Counter(2)) at (prev + 0, 38) to (start + 2, 10) +- Code(Expression(8, Sub)) at (prev + 3, 14) to (start + 0, 19) + = (c1 - c2) +- Code(Expression(8, Sub)) at (prev + 0, 24) to (start + 0, 27) + = (c1 - c2) +- Code(Expression(8, Sub)) at (prev + 0, 28) to (start + 0, 35) + = (c1 - c2) +- Code(Expression(10, Sub)) at (prev + 1, 17) to (start + 0, 20) + = (c0 - c7) +- Code(Expression(10, Sub)) at (prev + 0, 21) to (start + 0, 27) + = (c0 - c7) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c6 + diff --git a/tests/coverage/match.coverage b/tests/coverage/match.coverage new file mode 100644 index 0000000000000..a69a8652b3c75 --- /dev/null +++ b/tests/coverage/match.coverage @@ -0,0 +1,43 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| | + LL| |// Basic test for `match` expressions with various kinds of arms and guards. + LL| | + LL| 16|fn match_expr(x: Option, cond: bool) { + LL| 3| match x { + LL| 0| Some(0) => say("zero"), + LL| | Some(1) => { + LL| | // (block with a trailing expression) + LL| 1| say("one") + LL| | } + LL| 2| Some(2) => { + LL| 2| say("two"); + LL| 2| } + LL| 0| Some(3) if cond => { + LL| 0| say("three-cond"); + LL| 0| } + LL| 3| Some(3) => say("three"), + LL| 9| Some(other) if other == 4 => { + ^4 ^4 + LL| 4| say("four"); + LL| 4| } + LL| 5| Some(other) => say("other"), + LL| 1| None => say("none"), + LL| | } + LL| 16|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | for i in 0..=5 { + LL| | for _ in 0..i { + LL| | match_expr(Some(i), false); + LL| | } + LL| | } + LL| | match_expr(None, true); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/match.rs b/tests/coverage/match.rs new file mode 100644 index 0000000000000..c9d4fd75bdc18 --- /dev/null +++ b/tests/coverage/match.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 + +// Basic test for `match` expressions with various kinds of arms and guards. + +fn match_expr(x: Option, cond: bool) { + match x { + Some(0) => say("zero"), + Some(1) => { + // (block with a trailing expression) + say("one") + } + Some(2) => { + say("two"); + } + Some(3) if cond => { + say("three-cond"); + } + Some(3) => say("three"), + Some(other) if other == 4 => { + say("four"); + } + Some(other) => say("other"), + None => say("none"), + } +} + +#[coverage(off)] +fn main() { + for i in 0..=5 { + for _ in 0..i { + match_expr(Some(i), false); + } + } + match_expr(None, true); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map new file mode 100644 index 0000000000000..52bef0a80dfb1 --- /dev/null +++ b/tests/coverage/while.cov-map @@ -0,0 +1,42 @@ +Function name: while::while_with_tail_expr +Raw bytes (56): 0x[01, 01, 01, 05, 01, 0a, 01, 06, 01, 00, 1a, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 02, 01, 09, 00, 0f, 02, 01, 09, 00, 0c, 02, 00, 0d, 00, 1a, 01, 02, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/while.rs +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Counter(0) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) + = (c1 - c0) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 12) + = (c1 - c0) +- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 26) + = (c1 - c0) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 + +Function name: while::while_with_tail_stmt +Raw bytes (51): 0x[01, 01, 01, 05, 01, 09, 01, 0f, 01, 00, 1a, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 02, 00, 11, 03, 06, 02, 01, 09, 00, 0f, 01, 03, 05, 00, 08, 01, 00, 09, 00, 12, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/while.rs +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Counter(0) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 3, 6) + = (c1 - c0) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) + = (c1 - c0) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 + diff --git a/tests/coverage/while.coverage b/tests/coverage/while.coverage new file mode 100644 index 0000000000000..a83198bbc675e --- /dev/null +++ b/tests/coverage/while.coverage @@ -0,0 +1,34 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 + LL| | + LL| |// Basic test for `while` expressions. + LL| | + LL| 1|fn while_with_tail_expr() { + LL| 1| let mut x = 5; + LL| 6| while x > 0 { + LL| 5| x -= 1; + LL| 5| say("decreased x") + LL| | } + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| 1|fn while_with_tail_stmt() { + LL| 1| let mut x = 5; + LL| 6| while x > 0 { + LL| 5| x -= 1; + LL| 5| say("decreased x"); + LL| 5| } + LL| 1| say("goodbye"); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | while_with_tail_expr(); + LL| | while_with_tail_stmt(); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(msg: &str) { + LL| | println!("{msg}"); + LL| |} + diff --git a/tests/coverage/while.rs b/tests/coverage/while.rs new file mode 100644 index 0000000000000..77ef50d09a6ac --- /dev/null +++ b/tests/coverage/while.rs @@ -0,0 +1,33 @@ +#![feature(coverage_attribute)] +//@ edition: 2024 + +// Basic test for `while` expressions. + +fn while_with_tail_expr() { + let mut x = 5; + while x > 0 { + x -= 1; + say("decreased x") + } + say("goodbye"); +} + +fn while_with_tail_stmt() { + let mut x = 5; + while x > 0 { + x -= 1; + say("decreased x"); + } + say("goodbye"); +} + +#[coverage(off)] +fn main() { + while_with_tail_expr(); + while_with_tail_stmt(); +} + +#[coverage(off)] +fn say(msg: &str) { + println!("{msg}"); +} From 309c47ac1421b2165862aa32d4e453b927195755 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 10 Aug 2026 10:32:51 +0100 Subject: [PATCH 24/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 25/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 26/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 6072e6492b577f1c749d94346478bdd09bec7fb0 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Fri, 9 Jan 2026 22:53:40 +0000 Subject: [PATCH 27/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 49de62e884573d7316d74fc0da010b35c404e51d Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Mon, 15 Jun 2026 16:26:37 +0100 Subject: [PATCH 28/40] Adds tests for SVE inline asm Also blesses existing tests to make way for sve asm support --- tests/assembly-llvm/asm/aarch64-types.rs | 208 ++++++++++++++++++++++- tests/ui/asm/aarch64/aarch64-sve.rs | 1 + tests/ui/asm/aarch64/arm64ec-sve.rs | 2 + tests/ui/asm/aarch64/arm64ec-sve.stderr | 12 +- tests/ui/asm/aarch64/bad-reg.rs | 9 +- tests/ui/asm/aarch64/bad-reg.stderr | 40 ++--- tests/ui/asm/aarch64/type-check-2.stderr | 12 +- tests/ui/asm/aarch64/type-check-3.rs | 31 +++- tests/ui/asm/aarch64/type-check-3.stderr | 149 ++++++++++++---- tests/ui/asm/bad-template.aarch64.stderr | 4 +- tests/ui/asm/bad-template.x86_64.stderr | 4 +- tests/ui/asm/issue-87802.stderr | 2 +- tests/ui/asm/type-check-1.stderr | 6 +- tests/ui/asm/x86_64/type-check-2.stderr | 12 +- tests/ui/asm/x86_64/type-check-3.stderr | 16 +- 15 files changed, 399 insertions(+), 109 deletions(-) diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs index c171ba3b11e13..d720f00a5298f 100644 --- a/tests/assembly-llvm/asm/aarch64-types.rs +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -1,7 +1,7 @@ //@ add-minicore //@ revisions: aarch64 aarch64_be arm64ec //@ assembly-output: emit-asm -//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+sve //@ [aarch64] needs-llvm-components: aarch64 //@ [aarch64_be] compile-flags: --target aarch64_be-unknown-linux-gnu //@ [aarch64_be] needs-llvm-components: aarch64 @@ -9,7 +9,7 @@ //@ [arm64ec] needs-llvm-components: aarch64 //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, f16, f128)] +#![feature(no_core, f16, f128, rustc_attrs)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -20,6 +20,62 @@ use minicore::*; type ptr = *mut u8; +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(16)] +pub struct svint8_t(i8); + +#[cfg(target_feature = "sve")] +impl Copy for svint8_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(8)] +pub struct svint16_t(i16); + +#[cfg(target_feature = "sve")] +impl Copy for svint16_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(4)] +pub struct svint32_t(i32); + +#[cfg(target_feature = "sve")] +impl Copy for svint32_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(2)] +pub struct svint64_t(i64); + +#[cfg(target_feature = "sve")] +impl Copy for svint64_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(8)] +pub struct svfloat16_t(f16); + +#[cfg(target_feature = "sve")] +impl Copy for svfloat16_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(4)] +pub struct svfloat32_t(f32); + +#[cfg(target_feature = "sve")] +impl Copy for svfloat32_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(2)] +pub struct svfloat64_t(f64); + +#[cfg(target_feature = "sve")] +impl Copy for svfloat64_t {} + +#[cfg(target_feature = "sve")] +#[rustc_scalable_vector(16)] +pub struct svbool_t(bool); + +#[cfg(target_feature = "sve")] +impl Copy for svbool_t {} + extern "C" { fn extern_func(); static extern_static: u8; @@ -74,6 +130,24 @@ macro_rules! check { }; } +macro_rules! check_sve { + ($func:ident $ty:ident $class:ident $suffix:literal $zm:literal) => { + #[no_mangle] + pub unsafe fn $func(inp: &$ty, pred: &svbool_t) -> $ty { + let x = *inp; + let z = *pred; + let y; + asm!( + concat!("mov {0}.", $suffix, ", {1}/", $zm, ", {2}.", $suffix), + out($class) y, + in(preg) z, + in($class) x + ); + y + } + }; +} + macro_rules! check_reg { ($func:ident $ty:ident $reg:tt $mov:literal) => { // FIXME(f128): See FIXME in `check!` @@ -87,6 +161,24 @@ macro_rules! check_reg { }; } +macro_rules! check_reg_sve { + ($func:ident $ty:ident $reg:tt $suffix:literal $zm:literal) => { + #[no_mangle] + pub unsafe fn $func(inp: &$ty, pred: &svbool_t) -> $ty { + let x = *inp; + let z = *pred; + let y; + asm!( + concat!("mov ", $reg, ".", $suffix, ", {}/", $zm, ", ", $reg, ".", $suffix), + in(preg) z, + lateout($reg) y, + in($reg) x + ); + y + } + }; +} + // CHECK-LABEL: {{("#)?}}reg_i8{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} @@ -405,6 +497,62 @@ check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); // CHECK: //NO_APP check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_i8{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.b, p0/m, z{{[0-9]+}}.b +// aarch64: //NO_APP +check_sve!(zreg_i8 svint8_t zreg "b" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_i16{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h +// aarch64: //NO_APP +check_sve!(zreg_i16 svint16_t zreg "h" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_f16{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h +// aarch64: //NO_APP +check_sve!(zreg_f16 svfloat16_t zreg "h" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_i32{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s +// aarch64: //NO_APP +check_sve!(zreg_i32 svint32_t zreg "s" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_f32{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s +// aarch64: //NO_APP +check_sve!(zreg_f32 svfloat32_t zreg "s" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_i64{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d +// aarch64: //NO_APP +check_sve!(zreg_i64 svint64_t zreg "d" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_f64{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d +// aarch64: //NO_APP +check_sve!(zreg_f64 svfloat64_t zreg "d" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}zreg_bool{{"?}} +// aarch64: //APP +// aarch64: mov p{{[0-9]+}}.b, p{{[0-9]+}}/z, p{{[0-9]+}}.b +// aarch64: //NO_APP +check_sve!(zreg_bool svbool_t preg "b" "z"); + // CHECK-LABEL: {{("#)?}}x0_i8{{"?}} // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} @@ -501,6 +649,62 @@ check_reg!(v0_f64 f64 "s0" "fmov"); // CHECK: //NO_APP check_reg!(v0_f128 f128 "s0" "fmov"); +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_i8{{"?}} +// aarch64: //APP +// aarch64: mov z0.b, p0/m, z0.b +// aarch64: //NO_APP +check_reg_sve!(z0_i8 svint8_t "z0" "b" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_i16{{"?}} +// aarch64: //APP +// aarch64: mov z0.h, p0/m, z0.h +// aarch64: //NO_APP +check_reg_sve!(z0_i16 svint16_t "z0" "h" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_f16{{"?}} +// aarch64: //APP +// aarch64: mov z0.h, p0/m, z0.h +// aarch64: //NO_APP +check_reg_sve!(z0_f16 svfloat16_t "z0" "h" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_i32{{"?}} +// aarch64: //APP +// aarch64: mov z0.s, p0/m, z0.s +// aarch64: //NO_APP +check_reg_sve!(z0_i32 svint32_t "z0" "s" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_f32{{"?}} +// aarch64: //APP +// aarch64: mov z0.s, p0/m, z0.s +// aarch64: //NO_APP +check_reg_sve!(z0_f32 svfloat32_t "z0" "s" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_i64{{"?}} +// aarch64: //APP +// aarch64: mov z0.d, p0/m, z0.d +// aarch64: //NO_APP +check_reg_sve!(z0_i64 svint64_t "z0" "d" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}z0_f64{{"?}} +// aarch64: //APP +// aarch64: mov z0.d, p0/m, z0.d +// aarch64: //NO_APP +check_reg_sve!(z0_f64 svfloat64_t "z0" "d" "m"); + +#[cfg(target_feature = "sve")] +// aarch64-LABEL: {{("#)?}}p0_bool{{"?}} +// aarch64: //APP +// aarch64: mov p0.b, p1/z, p0.b +// aarch64: //NO_APP +check_reg_sve!(p0_bool svbool_t "p0" "b" "z"); + // CHECK-LABEL: {{("#)?}}v0_ptr{{"?}} // CHECK: //APP // CHECK: fmov s0, s0 diff --git a/tests/ui/asm/aarch64/aarch64-sve.rs b/tests/ui/asm/aarch64/aarch64-sve.rs index a146d73345554..daa4ab98dee75 100644 --- a/tests/ui/asm/aarch64/aarch64-sve.rs +++ b/tests/ui/asm/aarch64/aarch64-sve.rs @@ -15,6 +15,7 @@ use minicore::*; fn f(x: f64) { unsafe { asm!("", out("p0") _); + asm!("", out("z0") _); asm!("", out("ffr") _); } } diff --git a/tests/ui/asm/aarch64/arm64ec-sve.rs b/tests/ui/asm/aarch64/arm64ec-sve.rs index 05830aee8a974..3af9beeb58213 100644 --- a/tests/ui/asm/aarch64/arm64ec-sve.rs +++ b/tests/ui/asm/aarch64/arm64ec-sve.rs @@ -17,6 +17,8 @@ fn f(x: f64) { unsafe { asm!("", out("p0") _); //~^ ERROR cannot use register `p0` + asm!("", out("z0") _); + //~^ ERROR cannot use register `z0` asm!("", out("ffr") _); //~^ ERROR cannot use register `ffr` } diff --git a/tests/ui/asm/aarch64/arm64ec-sve.stderr b/tests/ui/asm/aarch64/arm64ec-sve.stderr index d654eb4ba1a19..2ee8a0b6546e9 100644 --- a/tests/ui/asm/aarch64/arm64ec-sve.stderr +++ b/tests/ui/asm/aarch64/arm64ec-sve.stderr @@ -1,14 +1,20 @@ -error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC +error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC --> $DIR/arm64ec-sve.rs:18:18 | LL | asm!("", out("p0") _); | ^^^^^^^^^^^ -error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC +error: cannot use register `z0`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC --> $DIR/arm64ec-sve.rs:20:18 | +LL | asm!("", out("z0") _); + | ^^^^^^^^^^^ + +error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC + --> $DIR/arm64ec-sve.rs:22:18 + | LL | asm!("", out("ffr") _); | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index 39a3e386bb6e5..95cd8a4331932 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -1,5 +1,5 @@ //@ add-minicore -//@ compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+neon +//@ compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+neon,+sve //@ needs-llvm-components: aarch64 //@ ignore-backends: gcc #![crate_type = "lib"] @@ -39,14 +39,11 @@ fn main() { //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", in("p0") foo); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output - //~| ERROR type `i32` cannot be used with this register class + //~^ ERROR type `i32` cannot be used with this register class asm!("", out("p0") _); asm!("{}", in(preg) foo); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output - //~| ERROR type `i32` cannot be used with this register class + //~^ ERROR type `i32` cannot be used with this register class asm!("{}", out(preg) _); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output // Explicit register conflicts // (except in/lateout which don't conflict) diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index 9f3d54eb46660..4e54ee85fec8c 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -4,7 +4,7 @@ error: invalid register class `foo`: unknown register class LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, and `preg` + = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, `zreg`, and `preg` error: invalid register `foo`: unknown register --> $DIR/bad-reg.rs:20:18 @@ -82,26 +82,8 @@ error: invalid register `x19`: x19 is used internally by LLVM and cannot be used LL | asm!("", in("x19") foo); | ^^^^^^^^^^^^^ -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:41:18 - | -LL | asm!("", in("p0") foo); - | ^^^^^^^^^^^^ - -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:45:20 - | -LL | asm!("{}", in(preg) foo); - | ^^^^^^^^^^^^ - -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:48:20 - | -LL | asm!("{}", out(preg) _); - | ^^^^^^^^^^^ - error: register `w0` conflicts with register `x0` - --> $DIR/bad-reg.rs:54:32 + --> $DIR/bad-reg.rs:51:32 | LL | asm!("", in("x0") foo, in("w0") bar); | ------------ ^^^^^^^^^^^^ register `w0` @@ -109,7 +91,7 @@ LL | asm!("", in("x0") foo, in("w0") bar); | register `x0` error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:56:32 + --> $DIR/bad-reg.rs:53:32 | LL | asm!("", in("x0") foo, out("x0") bar); | ------------ ^^^^^^^^^^^^^ register `x0` @@ -117,13 +99,13 @@ LL | asm!("", in("x0") foo, out("x0") bar); | register `x0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:56:18 + --> $DIR/bad-reg.rs:53:18 | LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:59:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("", in("v0") foo, in("q0") bar); | ------------ ^^^^^^^^^^^^ register `q0` @@ -131,7 +113,7 @@ LL | asm!("", in("v0") foo, in("q0") bar); | register `v0` error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:61:32 + --> $DIR/bad-reg.rs:58:32 | LL | asm!("", in("v0") foo, out("q0") bar); | ------------ ^^^^^^^^^^^^^ register `q0` @@ -139,7 +121,7 @@ LL | asm!("", in("v0") foo, out("q0") bar); | register `v0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:61:18 + --> $DIR/bad-reg.rs:58:18 | LL | asm!("", in("v0") foo, out("q0") bar); | ^^^^^^^^^^^^ @@ -150,15 +132,15 @@ error: type `i32` cannot be used with this register class LL | asm!("", in("p0") foo); | ^^^ | - = note: register class `preg` supports these types: + = note: register class `preg` supports these types: svbool_t error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:45:29 + --> $DIR/bad-reg.rs:44:29 | LL | asm!("{}", in(preg) foo); | ^^^ | - = note: register class `preg` supports these types: + = note: register class `preg` supports these types: svbool_t -error: aborting due to 20 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/asm/aarch64/type-check-2.stderr b/tests/ui/asm/aarch64/type-check-2.stderr index 2cd767db0334a..325e2c43b3035 100644 --- a/tests/ui/asm/aarch64/type-check-2.stderr +++ b/tests/ui/asm/aarch64/type-check-2.stderr @@ -12,7 +12,7 @@ error: cannot use value of type `{closure@$DIR/type-check-2.rs:32:28: 32:36}` fo LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec` for inline assembly --> $DIR/type-check-2.rs:34:28 @@ -20,7 +20,7 @@ error: cannot use value of type `Vec` for inline assembly LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `(i32, i32, i32)` for inline assembly --> $DIR/type-check-2.rs:36:28 @@ -28,7 +28,7 @@ error: cannot use value of type `(i32, i32, i32)` for inline assembly LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly --> $DIR/type-check-2.rs:38:28 @@ -36,7 +36,7 @@ error: cannot use value of type `[i32; 3]` for inline assembly LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly --> $DIR/type-check-2.rs:46:31 @@ -44,7 +44,7 @@ error: cannot use value of type `fn() {main}` for inline assembly LL | asm!("{}", inout(reg) f); | ^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly --> $DIR/type-check-2.rs:49:31 @@ -52,7 +52,7 @@ error: cannot use value of type `&mut i32` for inline assembly LL | asm!("{}", inout(reg) r); | ^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: aborting due to 7 previous errors diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index 2f8439d0a0f9e..168257fa26119 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -1,9 +1,9 @@ //@ only-aarch64 -//@ compile-flags: -C target-feature=+neon +//@ compile-flags: -C target-feature=+neon,+sve -#![feature(repr_simd)] +#![feature(repr_simd, stdarch_aarch64_sve)] -use std::arch::aarch64::float64x2_t; +use std::arch::aarch64::{float64x2_t, svdup_n_f64, svdup_n_s16, svdup_n_s32, svptrue_b8}; use std::arch::{asm, global_asm}; #[repr(simd)] @@ -13,6 +13,10 @@ struct Simd256bit([f64; 4]); fn main() { let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; let f64x4 = Simd256bit([0.0, 0.0, 0.0, 0.0]); + let svi16 = unsafe { svdup_n_s16(0i16) }; + let svi32 = unsafe { svdup_n_s32(0i32) }; + let svf64 = unsafe { svdup_n_f64(0f64) }; + let svb8 = unsafe { svptrue_b8() }; unsafe { // Types must be listed in the register class. @@ -33,6 +37,8 @@ fn main() { asm!("{:d}", in(vreg) 0f64); asm!("{:q}", in(vreg) f64x2); asm!("{:v}", in(vreg) f64x2); + asm!("{:z}", in(zreg) svi32); + asm!("{:p}", in(preg) svb8); // Should be the same as vreg asm!("{:q}", in(vreg_low16) f64x2); @@ -62,6 +68,12 @@ fn main() { //~^ WARN formatting may not be suitable for sub-register argument asm!("{}", in(vreg_low16) 0f64); //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) svi16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) svi32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) svf64); + //~^ WARN formatting may not be suitable for sub-register argument asm!("{0} {0}", in(reg) 0i16); //~^ WARN formatting may not be suitable for sub-register argument @@ -76,9 +88,20 @@ fn main() { //~^ ERROR type `float64x2_t` cannot be used with this register class asm!("{}", in(vreg) f64x4); //~^ ERROR type `Simd256bit` cannot be used with this register class + asm!("{}", in(reg) svi32); + //~^ ERROR type `svint32_t` cannot be used with this register class + asm!("{}", in(reg) svb8); + //~^ ERROR type `svbool_t` cannot be used with this register class + asm!("{}", in(vreg) svi32); + //~^ ERROR type `svint32_t` cannot be used with this register class + asm!("{}", in(vreg) svb8); + //~^ ERROR type `svbool_t` cannot be used with this register class + asm!("{}", in(preg) svi32); + //~^ ERROR type `svint32_t` cannot be used with this register class + asm!("{}", in(zreg) svb8); + //~^ ERROR type `svbool_t` cannot be used with this register class // Split inout operands must have compatible types - let mut val_i16: i16; let mut val_f32: f32; let mut val_u32: u32; diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr index 9d84d2666b33c..2840049b83ab1 100644 --- a/tests/ui/asm/aarch64/type-check-3.stderr +++ b/tests/ui/asm/aarch64/type-check-3.stderr @@ -1,96 +1,123 @@ warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:48:15 + --> $DIR/type-check-3.rs:54:15 | LL | asm!("{}", in(reg) 0u8); | ^^ --- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:50:15 + --> $DIR/type-check-3.rs:56:15 | LL | asm!("{}", in(reg) 0u16); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:52:15 + --> $DIR/type-check-3.rs:58:15 | LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:54:15 + --> $DIR/type-check-3.rs:60:15 | LL | asm!("{}", in(reg) 0f32); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:57:15 + --> $DIR/type-check-3.rs:63:15 | LL | asm!("{}", in(vreg) 0i16); | ^^ ---- for this argument | - = help: use `{0:h}` to have the register formatted as `h0` (for 16-bit values) - = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) + = help: use `{0:h}` to have the register formatted as `h0` (for 2-byte values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:59:15 + --> $DIR/type-check-3.rs:65:15 | LL | asm!("{}", in(vreg) 0f32); | ^^ ---- for this argument | - = help: use `{0:s}` to have the register formatted as `s0` (for 32-bit values) - = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) + = help: use `{0:s}` to have the register formatted as `s0` (for 4-byte values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:61:15 + --> $DIR/type-check-3.rs:67:15 | LL | asm!("{}", in(vreg) 0f64); | ^^ ---- for this argument | - = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values) - = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) + = help: use `{0:d}` to have the register formatted as `d0` (for 8-byte values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:63:15 + --> $DIR/type-check-3.rs:69:15 | LL | asm!("{}", in(vreg_low16) 0f64); | ^^ ---- for this argument | - = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values) - = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) + = help: use `{0:d}` to have the register formatted as `d0` (for 8-byte values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:66:15 + --> $DIR/type-check-3.rs:71:15 + | +LL | asm!("{}", in(zreg) svi16); + | ^^ ----- for this argument + | + = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) + = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:73:15 + | +LL | asm!("{}", in(zreg) svi32); + | ^^ ----- for this argument + | + = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) + = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:75:15 + | +LL | asm!("{}", in(zreg) svf64); + | ^^ ----- for this argument + | + = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) + = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:78:15 | LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:68:15 + --> $DIR/type-check-3.rs:80:15 | LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) error: type `i128` cannot be used with this register class - --> $DIR/type-check-3.rs:73:28 + --> $DIR/type-check-3.rs:85:28 | LL | asm!("{}", in(reg) 0i128); | ^^^^^ @@ -98,7 +125,7 @@ LL | asm!("{}", in(reg) 0i128); = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 error: type `float64x2_t` cannot be used with this register class - --> $DIR/type-check-3.rs:75:28 + --> $DIR/type-check-3.rs:87:28 | LL | asm!("{}", in(reg) f64x2); | ^^^^^ @@ -106,15 +133,63 @@ LL | asm!("{}", in(reg) f64x2); = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 error: type `Simd256bit` cannot be used with this register class - --> $DIR/type-check-3.rs:77:29 + --> $DIR/type-check-3.rs:89:29 | LL | asm!("{}", in(vreg) f64x4); | ^^^^^ | = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 +error: type `svint32_t` cannot be used with this register class + --> $DIR/type-check-3.rs:91:28 + | +LL | asm!("{}", in(reg) svi32); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 + +error: type `svbool_t` cannot be used with this register class + --> $DIR/type-check-3.rs:93:28 + | +LL | asm!("{}", in(reg) svb8); + | ^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 + +error: type `svint32_t` cannot be used with this register class + --> $DIR/type-check-3.rs:95:29 + | +LL | asm!("{}", in(vreg) svi32); + | ^^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + +error: type `svbool_t` cannot be used with this register class + --> $DIR/type-check-3.rs:97:29 + | +LL | asm!("{}", in(vreg) svb8); + | ^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + +error: type `svint32_t` cannot be used with this register class + --> $DIR/type-check-3.rs:99:29 + | +LL | asm!("{}", in(preg) svi32); + | ^^^^^ + | + = note: register class `preg` supports these types: svbool_t + +error: type `svbool_t` cannot be used with this register class + --> $DIR/type-check-3.rs:101:29 + | +LL | asm!("{}", in(zreg) svb8); + | ^^^^ + | + = note: register class `zreg` supports these types: svint8_t, svint16_t, svint32_t, svint64_t, svint128_t, svfloat26_t, svfloat32_t, svfloat64_t, svint128_t, svfloat128_t + error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:88:33 + --> $DIR/type-check-3.rs:111:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_f32); | ^^^^ ^^^^^^^ type `f32` @@ -124,7 +199,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_f32); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:90:33 + --> $DIR/type-check-3.rs:113:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); | ^^^^ ^^^^^^^ type `*mut u8` @@ -134,7 +209,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:92:33 + --> $DIR/type-check-3.rs:115:33 | LL | asm!("{:x}", inout(reg) main => val_u32); | ^^^^ ^^^^^^^ type `u32` @@ -143,5 +218,5 @@ LL | asm!("{:x}", inout(reg) main => val_u32); | = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size -error: aborting due to 6 previous errors; 10 warnings emitted +error: aborting due to 12 previous errors; 13 warnings emitted diff --git a/tests/ui/asm/bad-template.aarch64.stderr b/tests/ui/asm/bad-template.aarch64.stderr index 5f7ebb539107c..268fcceb14a50 100644 --- a/tests/ui/asm/bad-template.aarch64.stderr +++ b/tests/ui/asm/bad-template.aarch64.stderr @@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) - = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) + = help: use `{0:w}` to have the register formatted as `w0` (for 4-byte values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) = note: `#[warn(asm_sub_register)]` on by default error: aborting due to 21 previous errors; 1 warning emitted diff --git a/tests/ui/asm/bad-template.x86_64.stderr b/tests/ui/asm/bad-template.x86_64.stderr index 9947117621f1c..cc8626deeb5fa 100644 --- a/tests/ui/asm/bad-template.x86_64.stderr +++ b/tests/ui/asm/bad-template.x86_64.stderr @@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | - = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values) - = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) + = help: use `{0:e}` to have the register formatted as `eax` (for 4-byte values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 8-byte values) = note: `#[warn(asm_sub_register)]` on by default error: aborting due to 21 previous errors; 1 warning emitted diff --git a/tests/ui/asm/issue-87802.stderr b/tests/ui/asm/issue-87802.stderr index 64e91662919b2..da3f6815cd7da 100644 --- a/tests/ui/asm/issue-87802.stderr +++ b/tests/ui/asm/issue-87802.stderr @@ -4,7 +4,7 @@ error: cannot use value of type `!` for inline assembly LL | asm!("/* {0} */", out(reg) x); | ^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: aborting due to 1 previous error diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index aa9eed2fce65c..20e7017ee9ad5 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -43,7 +43,7 @@ error: cannot use value of type `[u64]` for inline assembly LL | asm!("{}", in(reg) v[..]); | ^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[u64]` for inline assembly --> $DIR/type-check-1.rs:23:29 @@ -51,7 +51,7 @@ error: cannot use value of type `[u64]` for inline assembly LL | asm!("{}", out(reg) v[..]); | ^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[u64]` for inline assembly --> $DIR/type-check-1.rs:26:31 @@ -59,7 +59,7 @@ error: cannot use value of type `[u64]` for inline assembly LL | asm!("{}", inout(reg) v[..]); | ^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: aborting due to 8 previous errors diff --git a/tests/ui/asm/x86_64/type-check-2.stderr b/tests/ui/asm/x86_64/type-check-2.stderr index e5d39b2fbd053..5e54f5af4c6d8 100644 --- a/tests/ui/asm/x86_64/type-check-2.stderr +++ b/tests/ui/asm/x86_64/type-check-2.stderr @@ -12,7 +12,7 @@ error: cannot use value of type `{closure@$DIR/type-check-2.rs:48:28: 48:36}` fo LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec` for inline assembly --> $DIR/type-check-2.rs:50:28 @@ -20,7 +20,7 @@ error: cannot use value of type `Vec` for inline assembly LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `(i32, i32, i32)` for inline assembly --> $DIR/type-check-2.rs:52:28 @@ -28,7 +28,7 @@ error: cannot use value of type `(i32, i32, i32)` for inline assembly LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly --> $DIR/type-check-2.rs:54:28 @@ -36,7 +36,7 @@ error: cannot use value of type `[i32; 3]` for inline assembly LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly --> $DIR/type-check-2.rs:62:31 @@ -44,7 +44,7 @@ error: cannot use value of type `fn() {main}` for inline assembly LL | asm!("{}", inout(reg) f); | ^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly --> $DIR/type-check-2.rs:65:31 @@ -52,7 +52,7 @@ error: cannot use value of type `&mut i32` for inline assembly LL | asm!("{}", inout(reg) r); | ^ | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: only integers, floats, SIMD vectors, scalable vectors, pointers and function pointers can be used as arguments for inline assembly error[E0381]: used binding `x` isn't initialized --> $DIR/type-check-2.rs:15:28 diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index ea9a3955e7078..e3ad64495904b 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -44,8 +44,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values) - = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) + = help: use `{0:x}` to have the register formatted as `ax` (for 2-byte values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 8-byte values) = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument @@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values) - = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) + = help: use `{0:x}` to have the register formatted as `ax` (for 2-byte values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 8-byte values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:36:15 @@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values) - = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) + = help: use `{0:e}` to have the register formatted as `eax` (for 4-byte values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 8-byte values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:39:15 @@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(ymm_reg) 0i64); | ^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `xmm0` (for 128-bit values) - = help: or use `{0:y}` to keep the default formatting of `ymm0` (for 256-bit values) + = help: use `{0:x}` to have the register formatted as `xmm0` (for 16-byte values) + = help: or use `{0:y}` to keep the default formatting of `ymm0` (for 32-byte values) error: type `i8` cannot be used with this register class --> $DIR/type-check-3.rs:50:28 From cbe88adf39be11ac9282d7142ac76fff37833025 Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Mon, 15 Jun 2026 16:26:37 +0100 Subject: [PATCH 29/40] Creates new `InlineAsmSize` enum Facilitates scalable vector support in inline assembly. --- .../rustc_codegen_cranelift/src/inline_asm.rs | 7 ++- compiler/rustc_hir_typeck/src/inline_asm.rs | 22 ++++++-- compiler/rustc_target/src/asm/aarch64.rs | 28 ++++++---- compiler/rustc_target/src/asm/amdgpu.rs | 2 +- compiler/rustc_target/src/asm/mod.rs | 56 ++++++++++--------- compiler/rustc_target/src/asm/x86.rs | 52 ++++++++++------- 6 files changed, 101 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index d4d64cb3fbaf2..cd2b06cc1defb 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -443,11 +443,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .supported_types(self.arch, true) .iter() .map(|(ty, _)| ty.size()) + .filter_map(InlineAsmSize::fixed_size_bytes) .max() - .unwrap(); - let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap(); + .expect("expected fixed-size type"); + let align = rustc_abi::Align::from_bytes(reg_size).unwrap(); let offset = slot_size.align_to(align); - *slot_size = offset + reg_size; + *slot_size = offset + rustc_abi::Size::from_bytes(reg_size); offset }; let mut new_slot = |x| new_slot_fn(&mut slot_size, x); diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 0e522b58ea280..ade0fde697061 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -13,7 +13,8 @@ use rustc_middle::ty::{ use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use rustc_target::asm::{ - InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, + InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmSize, InlineAsmType, + ModifierInfo, }; use rustc_trait_selection::infer::InferCtxtExt; @@ -177,10 +178,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { idx: usize, suggested_modifier: char, suggested_result: &'a str, - suggested_size: u16, + suggested_size: InlineAsmSize, default_modifier: char, default_result: &'a str, - default_size: u16, + default_size: InlineAsmSize, } impl<'a, 'b> Diagnostic<'a, ()> for FormattingSubRegisterArg<'b> { @@ -195,13 +196,24 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { default_result, default_size, } = self; + + fn format_size(size: InlineAsmSize) -> String { + match size { + InlineAsmSize::FixedBytes(size) => format!("{size}-byte values"), + InlineAsmSize::Scalable => "scalable values".to_string(), + } + } Diag::new(dcx, level, "formatting may not be suitable for sub-register argument") .with_span_label(expr_span, "for this argument") .with_help(format!( - "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as \ + `{suggested_result}` (for {})", + format_size(suggested_size) )) .with_help(format!( - "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of \ + `{default_result}` (for {})", + format_size(default_size) )) } } diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 2db8a7ff3020d..21a6582a9b046 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -1,9 +1,10 @@ +use core::convert::Into; use std::fmt; use rustc_data_structures::fx::FxIndexSet; use rustc_span::{Symbol, sym}; -use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use super::{InlineAsmArch, InlineAsmSize, InlineAsmType, ModifierInfo}; use crate::spec::{Env, Os, RelocModel, Target}; def_reg_class! { @@ -30,16 +31,17 @@ impl AArch64InlineAsmRegClass { pub fn suggest_modifier(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { - Self::reg => match ty.size().bits() { - 64 => None, - _ => Some(('w', "w0", 32).into()), + Self::reg => match ty.size() { + InlineAsmSize::FixedBytes(8) => None, + _ => Some(('w', "w0", InlineAsmSize::FixedBytes(4)).into()), }, - Self::vreg | Self::vreg_low16 => match ty.size().bits() { - 8 => Some(('b', "b0", 8).into()), - 16 => Some(('h', "h0", 16).into()), - 32 => Some(('s', "s0", 32).into()), - 64 => Some(('d', "d0", 64).into()), - 128 => Some(('q', "q0", 128).into()), + Self::vreg | Self::vreg_low16 => match ty.size() { + InlineAsmSize::FixedBytes(1) => Some(('b', "b0", ty.size()).into()), + InlineAsmSize::FixedBytes(2) => Some(('h', "h0", ty.size()).into()), + InlineAsmSize::FixedBytes(4) => Some(('s', "s0", ty.size()).into()), + InlineAsmSize::FixedBytes(8) => Some(('d', "d0", ty.size()).into()), + InlineAsmSize::FixedBytes(16) => Some(('q', "q0", ty.size()).into()), + InlineAsmSize::Scalable => Some(('z', "z0", InlineAsmSize::Scalable).into()), _ => None, }, Self::preg => None, @@ -48,9 +50,11 @@ impl AArch64InlineAsmRegClass { pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { match self { - Self::reg => Some(('x', "x0", 64).into()), - Self::vreg | Self::vreg_low16 => Some(('v', "v0", 128).into()), Self::preg => None, + Self::reg => Some(('x', "x0", InlineAsmSize::FixedBytes(8)).into()), + Self::vreg | Self::vreg_low16 => { + Some(('v', "v0", InlineAsmSize::FixedBytes(16)).into()) + } } } diff --git a/compiler/rustc_target/src/asm/amdgpu.rs b/compiler/rustc_target/src/asm/amdgpu.rs index 0f24ae5dea225..a344ad15bfa21 100644 --- a/compiler/rustc_target/src/asm/amdgpu.rs +++ b/compiler/rustc_target/src/asm/amdgpu.rs @@ -168,7 +168,7 @@ impl AmdgpuInlineAsmRegClass { return None; } - Some(Self::Vgpr(ty.size().bits().try_into().ok()?)) + Some(Self::Vgpr(ty.size().fixed_size_bytes().map(|byte| byte * 8)?.try_into().ok()?)) } pub fn suggest_modifier( diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 03301e50b489b..e1bf785b4eb54 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use std::fmt; -use rustc_abi::Size; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::Symbol; @@ -11,11 +10,11 @@ use crate::spec::{Arch, RelocModel, Target}; pub struct ModifierInfo { pub modifier: char, pub result: &'static str, - pub size: u16, + pub size: InlineAsmSize, } -impl From<(char, &'static str, u16)> for ModifierInfo { - fn from((modifier, result, size): (char, &'static str, u16)) -> Self { +impl From<(char, &'static str, InlineAsmSize)> for ModifierInfo { + fn from((modifier, result, size): (char, &'static str, InlineAsmSize)) -> Self { Self { modifier, result, size } } } @@ -798,32 +797,39 @@ pub enum InlineAsmType { VecF128(u64), } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum InlineAsmSize { + FixedBytes(u64), + Scalable, +} + +impl InlineAsmSize { + pub fn fixed_size_bytes(self) -> Option { + match self { + Self::FixedBytes(size) => Some(size), + Self::Scalable => None, + } + } +} + impl InlineAsmType { pub fn is_integer(self) -> bool { matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128) } - pub fn size(self) -> Size { - Size::from_bytes(match self { - Self::I8 => 1, - Self::I16 => 2, - Self::I32 => 4, - Self::I64 => 8, - Self::I128 => 16, - Self::F16 => 2, - Self::F32 => 4, - Self::F64 => 8, - Self::F128 => 16, - Self::VecI8(n) => n * 1, - Self::VecI16(n) => n * 2, - Self::VecI32(n) => n * 4, - Self::VecI64(n) => n * 8, - Self::VecI128(n) => n * 16, - Self::VecF16(n) => n * 2, - Self::VecF32(n) => n * 4, - Self::VecF64(n) => n * 8, - Self::VecF128(n) => n * 16, - }) + pub fn size(self) -> InlineAsmSize { + match self { + Self::I8 => InlineAsmSize::FixedBytes(1), + Self::I16 | Self::F16 => InlineAsmSize::FixedBytes(2), + Self::I32 | Self::F32 => InlineAsmSize::FixedBytes(4), + Self::I64 | Self::F64 => InlineAsmSize::FixedBytes(8), + Self::I128 | Self::F128 => InlineAsmSize::FixedBytes(16), + Self::VecI8(n) => InlineAsmSize::FixedBytes(n), + Self::VecI16(n) | Self::VecF16(n) => InlineAsmSize::FixedBytes(n * 2), + Self::VecI32(n) | Self::VecF32(n) => InlineAsmSize::FixedBytes(n * 4), + Self::VecI64(n) | Self::VecF64(n) => InlineAsmSize::FixedBytes(n * 8), + Self::VecI128(n) | Self::VecF128(n) => InlineAsmSize::FixedBytes(n * 16), + } } } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index c582c06d8f4bb..a4775db7e79f8 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -3,7 +3,7 @@ use std::fmt; use rustc_data_structures::fx::FxIndexSet; use rustc_span::Symbol; -use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use super::{InlineAsmArch, InlineAsmSize, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; def_reg_class! { @@ -49,33 +49,45 @@ impl X86InlineAsmRegClass { pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { - Self::reg | Self::reg_abcd if ty.size().bits() == 8 => Some(Self::reg_byte), + Self::reg | Self::reg_abcd if ty.size() == InlineAsmSize::FixedBytes(1) => { + Some(Self::reg_byte) + } _ => None, } } pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { - Self::reg => match ty.size().bits() { - 16 => Some(('x', "ax", 16).into()), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()), + Self::reg => match ty.size() { + InlineAsmSize::FixedBytes(2) => { + Some(('x', "ax", InlineAsmSize::FixedBytes(2)).into()) + } + InlineAsmSize::FixedBytes(4) if arch == InlineAsmArch::X86_64 => { + Some(('e', "eax", InlineAsmSize::FixedBytes(4)).into()) + } _ => None, }, - Self::reg_abcd => match ty.size().bits() { - 16 => Some(('x', "ax", 16).into()), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()), + Self::reg_abcd => match ty.size() { + InlineAsmSize::FixedBytes(2) => { + Some(('x', "ax", InlineAsmSize::FixedBytes(2)).into()) + } + InlineAsmSize::FixedBytes(4) if arch == InlineAsmArch::X86_64 => { + Some(('e', "eax", InlineAsmSize::FixedBytes(4)).into()) + } _ => None, }, Self::reg_byte => None, Self::xmm_reg => None, - Self::ymm_reg => match ty.size().bits() { - 256 => None, - _ => Some(('x', "xmm0", 128).into()), + Self::ymm_reg => match ty.size() { + InlineAsmSize::FixedBytes(32) => None, + _ => Some(('x', "xmm0", InlineAsmSize::FixedBytes(16)).into()), }, - Self::zmm_reg => match ty.size().bits() { - 512 => None, - 256 => Some(('y', "ymm0", 256).into()), - _ => Some(('x', "xmm0", 128).into()), + Self::zmm_reg => match ty.size() { + InlineAsmSize::FixedBytes(64) => None, + InlineAsmSize::FixedBytes(32) => { + Some(('y', "ymm0", InlineAsmSize::FixedBytes(32)).into()) + } + _ => Some(('x', "xmm0", InlineAsmSize::FixedBytes(16)).into()), }, Self::kreg | Self::kreg0 => None, Self::mmx_reg | Self::x87_reg => None, @@ -87,15 +99,15 @@ impl X86InlineAsmRegClass { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - Some(('r', "rax", 64).into()) + Some(('r', "rax", InlineAsmSize::FixedBytes(8)).into()) } else { - Some(('e', "eax", 32).into()) + Some(('e', "eax", InlineAsmSize::FixedBytes(4)).into()) } } Self::reg_byte => None, - Self::xmm_reg => Some(('x', "xmm0", 128).into()), - Self::ymm_reg => Some(('y', "ymm0", 256).into()), - Self::zmm_reg => Some(('z', "zmm0", 512).into()), + Self::xmm_reg => Some(('x', "xmm0", InlineAsmSize::FixedBytes(16)).into()), + Self::ymm_reg => Some(('y', "ymm0", InlineAsmSize::FixedBytes(32)).into()), + Self::zmm_reg => Some(('z', "zmm0", InlineAsmSize::FixedBytes(64)).into()), Self::kreg | Self::kreg0 => None, Self::mmx_reg | Self::x87_reg => None, Self::tmm_reg => None, From 7b2bfecd724492435f9d2d0f6cc796fc90e54299 Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Mon, 15 Jun 2026 16:26:37 +0100 Subject: [PATCH 30/40] Adds support for AArch64 SVE to inline assembly Adds new `zreg` register type and `SveVec*` variants to `InlineAsmType` --- compiler/rustc_codegen_gcc/src/asm.rs | 9 +- compiler/rustc_codegen_llvm/src/asm.rs | 14 ++- compiler/rustc_hir_typeck/src/inline_asm.rs | 26 ++++- compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_target/src/asm/aarch64.rs | 117 +++++++++++++------- compiler/rustc_target/src/asm/mod.rs | 30 +++++ 6 files changed, 151 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 5b17b4f83fea2..499b39951dea1 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -692,7 +692,8 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(AmdgpuInlineAsmRegClass::Sgpr(_)) => "Sg", @@ -807,7 +808,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(_) => cx.type_i32(), @@ -1056,7 +1058,8 @@ fn modifier_to_gcc( | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { if modifier == Some('v') { None } else { modifier } } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(_) => None, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index f9bcc6fe0b6ce..b85e54fc1e3d8 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -773,9 +773,13 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> // https://llvm.org/docs/LangRef.html#supported-constraint-code-list InlineAsmRegOrRegClass::RegClass(reg) => match reg { AArch64(AArch64InlineAsmRegClass::reg) => "r", - AArch64(AArch64InlineAsmRegClass::vreg) => "w", + AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::zreg) => { + "w" + } AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + // Although the above link suggests its just 'Upa', llvm's own tests seem to suggest its + // '@3Upa'. (see "src/llvm-project/clang/test/CodeGen/AArch64/sve-inline-asm-datatypes.c" line 139) + AArch64(AArch64InlineAsmRegClass::preg) => "@3Upa", Arm(ArmInlineAsmRegClass::reg) => "r", Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::dreg_low16) @@ -885,7 +889,8 @@ fn modifier_to_llvm( modifier } } - AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + AArch64(AArch64InlineAsmRegClass::zreg) => modifier, + AArch64(AArch64InlineAsmRegClass::preg) => modifier, Arm(ArmInlineAsmRegClass::reg) => None, Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => None, Arm(ArmInlineAsmRegClass::dreg) @@ -990,7 +995,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - AArch64(AArch64InlineAsmRegClass::preg) => unreachable!("clobber-only"), + AArch64(AArch64InlineAsmRegClass::zreg) => cx.type_scalable_vector(cx.type_i64(), 2), + AArch64(AArch64InlineAsmRegClass::preg) => cx.type_scalable_vector(cx.type_i1(), 16), Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), Arm(ArmInlineAsmRegClass::dreg) diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index ade0fde697061..e0fccce9577eb 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -159,6 +159,28 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { _ => Err(NonAsmTypeReason::InvalidElement(field.did, ty)), } } + ty::Adt(adt, _args) if adt.repr().scalable() => { + let (_element_count, elem_ty, _number_of_vectors) = + ty.scalable_vector_parts(self.tcx()).unwrap(); + + match elem_ty.kind() { + ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Ok(InlineAsmType::SveVecI8), + ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Ok(InlineAsmType::SveVecI16), + ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Ok(InlineAsmType::SveVecI32), + ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Ok(InlineAsmType::SveVecI64), + ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Ok(InlineAsmType::SveVecI128), + ty::Float(FloatTy::F16) => Ok(InlineAsmType::SveVecF16), + ty::Float(FloatTy::F32) => Ok(InlineAsmType::SveVecF32), + ty::Float(FloatTy::F64) => Ok(InlineAsmType::SveVecF64), + ty::Float(FloatTy::F128) => Ok(InlineAsmType::SveVecF128), + ty::Bool => Ok(InlineAsmType::SveVecBool), + _ => { + let fields = &adt.non_enum_variant().fields; + let field = &fields[FieldIdx::ZERO]; + Err(NonAsmTypeReason::InvalidElement(field.did, ty)) + } + } + } ty::Infer(_) => bug!("unexpected infer ty in asm operand"), _ => Err(NonAsmTypeReason::Invalid(ty)), } @@ -251,8 +273,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { NonAsmTypeReason::Invalid(ty) => { let msg = format!("cannot use value of type `{ty}` for inline assembly"); self.fcx.dcx().struct_span_err(expr.span, msg).with_note( - "only integers, floats, SIMD vectors, pointers and function pointers \ - can be used as arguments for inline assembly", + "only integers, floats, SIMD vectors, scalable vectors, pointers and function \ + pointers can be used as arguments for inline assembly", ).emit(); } NonAsmTypeReason::NotSizedPtr(ty) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 768f1be1cd48d..486e514d0d7eb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2067,6 +2067,7 @@ symbols! { suggestion, super_let, supertrait_item_shadowing, + sve, sve_cast, sve_tuple_create2, sve_tuple_create3, @@ -2406,6 +2407,7 @@ symbols! { zfh, zfhmin, zmm_reg, + zreg, ztso, // tidy-alphabetical-end } diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 21a6582a9b046..75c39cb1031bd 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -12,6 +12,7 @@ def_reg_class! { reg, vreg, vreg_low16, + zreg, preg, } } @@ -21,7 +22,8 @@ impl AArch64InlineAsmRegClass { match self { Self::reg => &['w', 'x'], Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'], - Self::preg => &[], + Self::zreg => &['z'], + Self::preg => &['p'], } } @@ -44,17 +46,19 @@ impl AArch64InlineAsmRegClass { InlineAsmSize::Scalable => Some(('z', "z0", InlineAsmSize::Scalable).into()), _ => None, }, - Self::preg => None, + Self::zreg => Some(('z', "z0", ty.size()).into()), + Self::preg => Some(('p', "p0", ty.size()).into()), } } pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { match self { - Self::preg => None, Self::reg => Some(('x', "x0", InlineAsmSize::FixedBytes(8)).into()), Self::vreg | Self::vreg_low16 => { Some(('v', "v0", InlineAsmSize::FixedBytes(16)).into()) } + Self::zreg => Some(('z', "z0", InlineAsmSize::Scalable).into()), + Self::preg => Some(('p', "p0", InlineAsmSize::Scalable).into()), } } @@ -68,9 +72,14 @@ impl AArch64InlineAsmRegClass { neon: I8, I16, I32, I64, F16, F32, F64, F128, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1), VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - // Note: When adding support for SVE vector types, they must be rejected for Arm64EC. }, - Self::preg => &[], + Self::zreg => types! { + sve: SveVecI8, SveVecI16, SveVecI32, SveVecI64, SveVecI128, SveVecF16, SveVecF32, + SveVecF64, SveVecI128, SveVecF128; + }, + Self::preg => types! { + sve: SveVecBool; + }, } } } @@ -109,7 +118,7 @@ fn restricted_for_arm64ec( _is_clobber: bool, ) -> Result<(), &'static str> { if arch == InlineAsmArch::Arm64EC { - Err("x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC") + Err("x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC") } else { Ok(()) } @@ -146,38 +155,70 @@ def_regs! { x27: reg = ["x27", "w27"], x28: reg = ["x28", "w28"] % restricted_for_arm64ec, x30: reg = ["x30", "w30", "lr", "wlr"], - v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"], - v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"], - v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2", "z2"], - v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3", "z3"], - v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4", "z4"], - v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5", "z5"], - v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6", "z6"], - v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7", "z7"], - v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8", "z8"], - v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9", "z9"], - v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10", "z10"], - v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11", "z11"], - v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12", "z12"], - v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"], - v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"], - v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"], - v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"] % restricted_for_arm64ec, - v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"] % restricted_for_arm64ec, - v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"] % restricted_for_arm64ec, - v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"] % restricted_for_arm64ec, - v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"] % restricted_for_arm64ec, - v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"] % restricted_for_arm64ec, - v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"] % restricted_for_arm64ec, - v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"] % restricted_for_arm64ec, - v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"] % restricted_for_arm64ec, - v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"] % restricted_for_arm64ec, - v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"] % restricted_for_arm64ec, - v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"] % restricted_for_arm64ec, - v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"] % restricted_for_arm64ec, - v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec, - v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec, - v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec, + v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"], + v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"], + v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"], + v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"], + v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"], + v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"], + v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"], + v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"], + v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"], + v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"], + v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"], + v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"], + v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"], + v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"], + v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"], + v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"], + v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"] % restricted_for_arm64ec, + v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"] % restricted_for_arm64ec, + v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"] % restricted_for_arm64ec, + v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"] % restricted_for_arm64ec, + v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"] % restricted_for_arm64ec, + v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"] % restricted_for_arm64ec, + v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"] % restricted_for_arm64ec, + v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"] % restricted_for_arm64ec, + v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"] % restricted_for_arm64ec, + v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"] % restricted_for_arm64ec, + v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"] % restricted_for_arm64ec, + v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"] % restricted_for_arm64ec, + v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"] % restricted_for_arm64ec, + v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"] % restricted_for_arm64ec, + v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"] % restricted_for_arm64ec, + v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"] % restricted_for_arm64ec, + z0: zreg = ["z0"] % restricted_for_arm64ec, + z1: zreg = ["z1"] % restricted_for_arm64ec, + z2: zreg = ["z2"] % restricted_for_arm64ec, + z3: zreg = ["z3"] % restricted_for_arm64ec, + z4: zreg = ["z4"] % restricted_for_arm64ec, + z5: zreg = ["z5"] % restricted_for_arm64ec, + z6: zreg = ["z6"] % restricted_for_arm64ec, + z7: zreg = ["z7"] % restricted_for_arm64ec, + z8: zreg = ["z8"] % restricted_for_arm64ec, + z9: zreg = ["z9"] % restricted_for_arm64ec, + z10: zreg = ["z10"] % restricted_for_arm64ec, + z11: zreg = ["z11"] % restricted_for_arm64ec, + z12: zreg = ["z12"] % restricted_for_arm64ec, + z13: zreg = ["z13"] % restricted_for_arm64ec, + z14: zreg = ["z14"] % restricted_for_arm64ec, + z15: zreg = ["z15"] % restricted_for_arm64ec, + z16: zreg = ["z16"] % restricted_for_arm64ec, + z17: zreg = ["z17"] % restricted_for_arm64ec, + z18: zreg = ["z18"] % restricted_for_arm64ec, + z19: zreg = ["z19"] % restricted_for_arm64ec, + z20: zreg = ["z20"] % restricted_for_arm64ec, + z21: zreg = ["z21"] % restricted_for_arm64ec, + z22: zreg = ["z22"] % restricted_for_arm64ec, + z23: zreg = ["z23"] % restricted_for_arm64ec, + z24: zreg = ["z24"] % restricted_for_arm64ec, + z25: zreg = ["z25"] % restricted_for_arm64ec, + z26: zreg = ["z26"] % restricted_for_arm64ec, + z27: zreg = ["z27"] % restricted_for_arm64ec, + z28: zreg = ["z28"] % restricted_for_arm64ec, + z29: zreg = ["z29"] % restricted_for_arm64ec, + z30: zreg = ["z30"] % restricted_for_arm64ec, + z31: zreg = ["z31"] % restricted_for_arm64ec, p0: preg = ["p0"] % restricted_for_arm64ec, p1: preg = ["p1"] % restricted_for_arm64ec, p2: preg = ["p2"] % restricted_for_arm64ec, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index e1bf785b4eb54..c0ed24065180b 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -795,6 +795,16 @@ pub enum InlineAsmType { VecF32(u64), VecF64(u64), VecF128(u64), + SveVecI8, + SveVecI16, + SveVecI32, + SveVecI64, + SveVecI128, + SveVecF16, + SveVecF32, + SveVecF64, + SveVecF128, + SveVecBool, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -829,6 +839,16 @@ impl InlineAsmType { Self::VecI32(n) | Self::VecF32(n) => InlineAsmSize::FixedBytes(n * 4), Self::VecI64(n) | Self::VecF64(n) => InlineAsmSize::FixedBytes(n * 8), Self::VecI128(n) | Self::VecF128(n) => InlineAsmSize::FixedBytes(n * 16), + Self::SveVecI8 + | Self::SveVecI16 + | Self::SveVecI32 + | Self::SveVecI64 + | Self::SveVecI128 + | Self::SveVecF16 + | Self::SveVecF32 + | Self::SveVecF64 + | Self::SveVecF128 + | Self::SveVecBool => InlineAsmSize::Scalable, } } } @@ -854,6 +874,16 @@ impl fmt::Display for InlineAsmType { Self::VecF32(n) => write!(f, "f32x{n}"), Self::VecF64(n) => write!(f, "f64x{n}"), Self::VecF128(n) => write!(f, "f128x{n}"), + Self::SveVecI8 => f.write_str("svint8_t"), + Self::SveVecI16 => f.write_str("svint16_t"), + Self::SveVecI32 => f.write_str("svint32_t"), + Self::SveVecI64 => f.write_str("svint64_t"), + Self::SveVecI128 => f.write_str("svint128_t"), + Self::SveVecF16 => f.write_str("svfloat26_t"), + Self::SveVecF32 => f.write_str("svfloat32_t"), + Self::SveVecF64 => f.write_str("svfloat64_t"), + Self::SveVecF128 => f.write_str("svfloat128_t"), + Self::SveVecBool => f.write_str("svbool_t"), } } } From 51b3f52eab0e629de344d5e964f9b2a7a6ce57ba Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 25 Aug 2026 03:27:05 +0100 Subject: [PATCH 31/40] Merge zreg into vreg and keep ffr in a clobber-only class --- compiler/rustc_codegen_gcc/src/asm.rs | 15 ++- compiler/rustc_codegen_llvm/src/asm.rs | 27 +++-- compiler/rustc_span/src/symbol.rs | 2 +- compiler/rustc_target/src/asm/aarch64.rs | 118 +++++++------------ tests/assembly-llvm/asm/aarch64-modifiers.rs | 8 +- tests/assembly-llvm/asm/aarch64-types.rs | 114 ++++++++++++------ tests/ui/asm/aarch64/arm64ec-sve.rs | 2 - tests/ui/asm/aarch64/arm64ec-sve.stderr | 12 +- tests/ui/asm/aarch64/bad-reg.rs | 15 ++- tests/ui/asm/aarch64/bad-reg.stderr | 54 ++++++--- tests/ui/asm/aarch64/type-check-3.rs | 15 +-- tests/ui/asm/aarch64/type-check-3.stderr | 80 +++++-------- 12 files changed, 235 insertions(+), 227 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 499b39951dea1..8fd438d847d29 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -692,8 +692,9 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64( + AArch64InlineAsmRegClass::preg | AArch64InlineAsmRegClass::ffr, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(AmdgpuInlineAsmRegClass::Sgpr(_)) => "Sg", @@ -808,8 +809,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64( + AArch64InlineAsmRegClass::preg | AArch64InlineAsmRegClass::ffr, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(_) => cx.type_i32(), @@ -1058,8 +1060,9 @@ fn modifier_to_gcc( | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { if modifier == Some('v') { None } else { modifier } } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64( + AArch64InlineAsmRegClass::preg | AArch64InlineAsmRegClass::ffr, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::Amdgpu(_) => None, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b85e54fc1e3d8..3d2362be02f27 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -732,18 +732,25 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> format!("{{{}{}}}", class, idx) } } else if let Some(idx) = a64_vreg_index(reg) { - let class = if let Some(layout) = layout { - match layout.size.bytes() { + let class = match layout { + Some(layout) + if matches!( + layout.backend_repr, + BackendRepr::SimdScalableVector { .. } + ) => + { + 'z' + } + Some(layout) => match layout.size.bytes() { 16 => 'q', 8 => 'd', 4 => 's', 2 => 'h', 1 => 'd', // We fixup i8 to i8x8 _ => unreachable!(), - } - } else { + }, // We use i64x2 as the type for discarded outputs - 'q' + None => 'q', }; format!("{{{}{}}}", class, idx) } else if let Some(idx) = hexagon_reg_pair_index(reg) { @@ -773,13 +780,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> // https://llvm.org/docs/LangRef.html#supported-constraint-code-list InlineAsmRegOrRegClass::RegClass(reg) => match reg { AArch64(AArch64InlineAsmRegClass::reg) => "r", - AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::zreg) => { - "w" - } + AArch64(AArch64InlineAsmRegClass::vreg) => "w", AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", // Although the above link suggests its just 'Upa', llvm's own tests seem to suggest its // '@3Upa'. (see "src/llvm-project/clang/test/CodeGen/AArch64/sve-inline-asm-datatypes.c" line 139) AArch64(AArch64InlineAsmRegClass::preg) => "@3Upa", + AArch64(AArch64InlineAsmRegClass::ffr) => unreachable!("clobber-only"), Arm(ArmInlineAsmRegClass::reg) => "r", Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::dreg_low16) @@ -889,8 +895,7 @@ fn modifier_to_llvm( modifier } } - AArch64(AArch64InlineAsmRegClass::zreg) => modifier, - AArch64(AArch64InlineAsmRegClass::preg) => modifier, + AArch64(AArch64InlineAsmRegClass::preg | AArch64InlineAsmRegClass::ffr) => None, Arm(ArmInlineAsmRegClass::reg) => None, Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => None, Arm(ArmInlineAsmRegClass::dreg) @@ -995,8 +1000,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - AArch64(AArch64InlineAsmRegClass::zreg) => cx.type_scalable_vector(cx.type_i64(), 2), AArch64(AArch64InlineAsmRegClass::preg) => cx.type_scalable_vector(cx.type_i1(), 16), + AArch64(AArch64InlineAsmRegClass::ffr) => unreachable!("clobber-only"), Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), Arm(ArmInlineAsmRegClass::dreg) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 486e514d0d7eb..7665df4a4e5ae 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -957,6 +957,7 @@ symbols! { ffi_const, ffi_pure, ffi_returns_twice, + ffr, field, field_base, field_init_shorthand, @@ -2407,7 +2408,6 @@ symbols! { zfh, zfhmin, zmm_reg, - zreg, ztso, // tidy-alphabetical-end } diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 75c39cb1031bd..39dfd6c3bb070 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -12,8 +12,8 @@ def_reg_class! { reg, vreg, vreg_low16, - zreg, preg, + ffr, } } @@ -21,9 +21,8 @@ impl AArch64InlineAsmRegClass { pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { match self { Self::reg => &['w', 'x'], - Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'], - Self::zreg => &['z'], - Self::preg => &['p'], + Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v', 'z'], + Self::preg | Self::ffr => &[], } } @@ -46,8 +45,7 @@ impl AArch64InlineAsmRegClass { InlineAsmSize::Scalable => Some(('z', "z0", InlineAsmSize::Scalable).into()), _ => None, }, - Self::zreg => Some(('z', "z0", ty.size()).into()), - Self::preg => Some(('p', "p0", ty.size()).into()), + Self::preg | Self::ffr => None, } } @@ -57,8 +55,7 @@ impl AArch64InlineAsmRegClass { Self::vreg | Self::vreg_low16 => { Some(('v', "v0", InlineAsmSize::FixedBytes(16)).into()) } - Self::zreg => Some(('z', "z0", InlineAsmSize::Scalable).into()), - Self::preg => Some(('p', "p0", InlineAsmSize::Scalable).into()), + Self::preg | Self::ffr => None, } } @@ -72,14 +69,13 @@ impl AArch64InlineAsmRegClass { neon: I8, I16, I32, I64, F16, F32, F64, F128, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1), VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - }, - Self::zreg => types! { sve: SveVecI8, SveVecI16, SveVecI32, SveVecI64, SveVecI128, SveVecF16, SveVecF32, - SveVecF64, SveVecI128, SveVecF128; + SveVecF64, SveVecI128, SveVecF128; }, Self::preg => types! { sve: SveVecBool; }, + Self::ffr => &[], } } } @@ -118,7 +114,7 @@ fn restricted_for_arm64ec( _is_clobber: bool, ) -> Result<(), &'static str> { if arch == InlineAsmArch::Arm64EC { - Err("x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC") + Err("x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC") } else { Ok(()) } @@ -155,70 +151,38 @@ def_regs! { x27: reg = ["x27", "w27"], x28: reg = ["x28", "w28"] % restricted_for_arm64ec, x30: reg = ["x30", "w30", "lr", "wlr"], - v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"], - v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"], - v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"], - v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"], - v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"], - v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"], - v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"], - v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"], - v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"], - v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"], - v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"], - v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"], - v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"], - v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"], - v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"], - v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"], - v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"] % restricted_for_arm64ec, - v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"] % restricted_for_arm64ec, - v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"] % restricted_for_arm64ec, - v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"] % restricted_for_arm64ec, - v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"] % restricted_for_arm64ec, - v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"] % restricted_for_arm64ec, - v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"] % restricted_for_arm64ec, - v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"] % restricted_for_arm64ec, - v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"] % restricted_for_arm64ec, - v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"] % restricted_for_arm64ec, - v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"] % restricted_for_arm64ec, - v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"] % restricted_for_arm64ec, - v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"] % restricted_for_arm64ec, - v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"] % restricted_for_arm64ec, - v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"] % restricted_for_arm64ec, - v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"] % restricted_for_arm64ec, - z0: zreg = ["z0"] % restricted_for_arm64ec, - z1: zreg = ["z1"] % restricted_for_arm64ec, - z2: zreg = ["z2"] % restricted_for_arm64ec, - z3: zreg = ["z3"] % restricted_for_arm64ec, - z4: zreg = ["z4"] % restricted_for_arm64ec, - z5: zreg = ["z5"] % restricted_for_arm64ec, - z6: zreg = ["z6"] % restricted_for_arm64ec, - z7: zreg = ["z7"] % restricted_for_arm64ec, - z8: zreg = ["z8"] % restricted_for_arm64ec, - z9: zreg = ["z9"] % restricted_for_arm64ec, - z10: zreg = ["z10"] % restricted_for_arm64ec, - z11: zreg = ["z11"] % restricted_for_arm64ec, - z12: zreg = ["z12"] % restricted_for_arm64ec, - z13: zreg = ["z13"] % restricted_for_arm64ec, - z14: zreg = ["z14"] % restricted_for_arm64ec, - z15: zreg = ["z15"] % restricted_for_arm64ec, - z16: zreg = ["z16"] % restricted_for_arm64ec, - z17: zreg = ["z17"] % restricted_for_arm64ec, - z18: zreg = ["z18"] % restricted_for_arm64ec, - z19: zreg = ["z19"] % restricted_for_arm64ec, - z20: zreg = ["z20"] % restricted_for_arm64ec, - z21: zreg = ["z21"] % restricted_for_arm64ec, - z22: zreg = ["z22"] % restricted_for_arm64ec, - z23: zreg = ["z23"] % restricted_for_arm64ec, - z24: zreg = ["z24"] % restricted_for_arm64ec, - z25: zreg = ["z25"] % restricted_for_arm64ec, - z26: zreg = ["z26"] % restricted_for_arm64ec, - z27: zreg = ["z27"] % restricted_for_arm64ec, - z28: zreg = ["z28"] % restricted_for_arm64ec, - z29: zreg = ["z29"] % restricted_for_arm64ec, - z30: zreg = ["z30"] % restricted_for_arm64ec, - z31: zreg = ["z31"] % restricted_for_arm64ec, + v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"], + v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"], + v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2", "z2"], + v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3", "z3"], + v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4", "z4"], + v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5", "z5"], + v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6", "z6"], + v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7", "z7"], + v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8", "z8"], + v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9", "z9"], + v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10", "z10"], + v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11", "z11"], + v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12", "z12"], + v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"], + v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"], + v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"], + v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"] % restricted_for_arm64ec, + v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"] % restricted_for_arm64ec, + v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"] % restricted_for_arm64ec, + v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"] % restricted_for_arm64ec, + v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"] % restricted_for_arm64ec, + v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"] % restricted_for_arm64ec, + v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"] % restricted_for_arm64ec, + v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"] % restricted_for_arm64ec, + v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"] % restricted_for_arm64ec, + v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"] % restricted_for_arm64ec, + v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"] % restricted_for_arm64ec, + v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"] % restricted_for_arm64ec, + v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"] % restricted_for_arm64ec, + v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec, + v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec, + v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec, p0: preg = ["p0"] % restricted_for_arm64ec, p1: preg = ["p1"] % restricted_for_arm64ec, p2: preg = ["p2"] % restricted_for_arm64ec, @@ -235,7 +199,7 @@ def_regs! { p13: preg = ["p13"] % restricted_for_arm64ec, p14: preg = ["p14"] % restricted_for_arm64ec, p15: preg = ["p15"] % restricted_for_arm64ec, - ffr: preg = ["ffr"] % restricted_for_arm64ec, + ffr: ffr = ["ffr"] % restricted_for_arm64ec, #error = ["x19", "w19"] => "x19 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["x29", "w29", "fp", "wfp"] => diff --git a/tests/assembly-llvm/asm/aarch64-modifiers.rs b/tests/assembly-llvm/asm/aarch64-modifiers.rs index 6cb028461ddd1..66be35de574f6 100644 --- a/tests/assembly-llvm/asm/aarch64-modifiers.rs +++ b/tests/assembly-llvm/asm/aarch64-modifiers.rs @@ -1,7 +1,7 @@ //@ add-minicore //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 -C panic=abort -//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+sve //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: aarch64 @@ -85,6 +85,12 @@ check!(vreg_q vreg "ldr {:q}, [x0]"); // CHECK: //NO_APP check!(vreg_v vreg "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); +// CHECK-LABEL: vreg_z: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check!(vreg_z vreg "mov {0:z}.d, {0:z}.d"); + // CHECK-LABEL: vreg_low16: // CHECK: //APP // CHECK: add v0.4s, v0.4s, v0.4s diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs index d720f00a5298f..64a54a208ba54 100644 --- a/tests/assembly-llvm/asm/aarch64-types.rs +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -132,16 +132,17 @@ macro_rules! check { macro_rules! check_sve { ($func:ident $ty:ident $class:ident $suffix:literal $zm:literal) => { + #[cfg(target_feature = "sve")] #[no_mangle] pub unsafe fn $func(inp: &$ty, pred: &svbool_t) -> $ty { let x = *inp; let z = *pred; let y; asm!( - concat!("mov {0}.", $suffix, ", {1}/", $zm, ", {2}.", $suffix), + concat!("mov {0}.", $suffix, ", p0/", $zm, ", {1}.", $suffix), out($class) y, - in(preg) z, - in($class) x + in($class) x, + in("p0") z ); y } @@ -163,14 +164,15 @@ macro_rules! check_reg { macro_rules! check_reg_sve { ($func:ident $ty:ident $reg:tt $suffix:literal $zm:literal) => { + #[cfg(target_feature = "sve")] #[no_mangle] pub unsafe fn $func(inp: &$ty, pred: &svbool_t) -> $ty { let x = *inp; let z = *pred; let y; asm!( - concat!("mov ", $reg, ".", $suffix, ", {}/", $zm, ", ", $reg, ".", $suffix), - in(preg) z, + concat!("mov ", $reg, ".", $suffix, ", p0/", $zm, ", ", $reg, ".", $suffix), + in("p0") z, lateout($reg) y, in($reg) x ); @@ -497,61 +499,95 @@ check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); // CHECK: //NO_APP check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_i8{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_i8{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.b, p0/m, z{{[0-9]+}}.b // aarch64: //NO_APP -check_sve!(zreg_i8 svint8_t zreg "b" "m"); +check_sve!(vreg_sve_i8 svint8_t vreg "b" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_i16{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_i16{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h // aarch64: //NO_APP -check_sve!(zreg_i16 svint16_t zreg "h" "m"); +check_sve!(vreg_sve_i16 svint16_t vreg "h" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_f16{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_f16{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h // aarch64: //NO_APP -check_sve!(zreg_f16 svfloat16_t zreg "h" "m"); +check_sve!(vreg_sve_f16 svfloat16_t vreg "h" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_i32{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_i32{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s // aarch64: //NO_APP -check_sve!(zreg_i32 svint32_t zreg "s" "m"); +check_sve!(vreg_sve_i32 svint32_t vreg "s" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_f32{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_f32{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s // aarch64: //NO_APP -check_sve!(zreg_f32 svfloat32_t zreg "s" "m"); +check_sve!(vreg_sve_f32 svfloat32_t vreg "s" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_i64{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_i64{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d // aarch64: //NO_APP -check_sve!(zreg_i64 svint64_t zreg "d" "m"); +check_sve!(vreg_sve_i64 svint64_t vreg "d" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_f64{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_sve_f64{{"?}} // aarch64: //APP // aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d // aarch64: //NO_APP -check_sve!(zreg_f64 svfloat64_t zreg "d" "m"); +check_sve!(vreg_sve_f64 svfloat64_t vreg "d" "m"); -#[cfg(target_feature = "sve")] -// aarch64-LABEL: {{("#)?}}zreg_bool{{"?}} +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_i8{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.b, p0/m, z{{[0-9]+}}.b +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_i8 svint8_t vreg_low16 "b" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_i16{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_i16 svint16_t vreg_low16 "h" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_f16{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.h, p0/m, z{{[0-9]+}}.h +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_f16 svfloat16_t vreg_low16 "h" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_i32{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_i32 svint32_t vreg_low16 "s" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_f32{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.s, p0/m, z{{[0-9]+}}.s +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_f32 svfloat32_t vreg_low16 "s" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_i64{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_i64 svint64_t vreg_low16 "d" "m"); + +// aarch64-LABEL: {{("#)?}}vreg_low16_sve_f64{{"?}} +// aarch64: //APP +// aarch64: mov z{{[0-9]+}}.d, p0/m, z{{[0-9]+}}.d +// aarch64: //NO_APP +check_sve!(vreg_low16_sve_f64 svfloat64_t vreg_low16 "d" "m"); + +// aarch64-LABEL: {{("#)?}}preg_bool{{"?}} // aarch64: //APP -// aarch64: mov p{{[0-9]+}}.b, p{{[0-9]+}}/z, p{{[0-9]+}}.b +// aarch64: mov p{{[0-9]+}}.b, p0/z, p{{[0-9]+}}.b // aarch64: //NO_APP -check_sve!(zreg_bool svbool_t preg "b" "z"); +check_sve!(preg_bool svbool_t preg "b" "z"); // CHECK-LABEL: {{("#)?}}x0_i8{{"?}} // CHECK: //APP @@ -649,61 +685,61 @@ check_reg!(v0_f64 f64 "s0" "fmov"); // CHECK: //NO_APP check_reg!(v0_f128 f128 "s0" "fmov"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_i8{{"?}} // aarch64: //APP // aarch64: mov z0.b, p0/m, z0.b // aarch64: //NO_APP check_reg_sve!(z0_i8 svint8_t "z0" "b" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_i16{{"?}} // aarch64: //APP // aarch64: mov z0.h, p0/m, z0.h // aarch64: //NO_APP check_reg_sve!(z0_i16 svint16_t "z0" "h" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_f16{{"?}} // aarch64: //APP // aarch64: mov z0.h, p0/m, z0.h // aarch64: //NO_APP check_reg_sve!(z0_f16 svfloat16_t "z0" "h" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_i32{{"?}} // aarch64: //APP // aarch64: mov z0.s, p0/m, z0.s // aarch64: //NO_APP check_reg_sve!(z0_i32 svint32_t "z0" "s" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_f32{{"?}} // aarch64: //APP // aarch64: mov z0.s, p0/m, z0.s // aarch64: //NO_APP check_reg_sve!(z0_f32 svfloat32_t "z0" "s" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_i64{{"?}} // aarch64: //APP // aarch64: mov z0.d, p0/m, z0.d // aarch64: //NO_APP check_reg_sve!(z0_i64 svint64_t "z0" "d" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}z0_f64{{"?}} // aarch64: //APP // aarch64: mov z0.d, p0/m, z0.d // aarch64: //NO_APP check_reg_sve!(z0_f64 svfloat64_t "z0" "d" "m"); -#[cfg(target_feature = "sve")] // aarch64-LABEL: {{("#)?}}p0_bool{{"?}} // aarch64: //APP // aarch64: mov p0.b, p1/z, p0.b // aarch64: //NO_APP -check_reg_sve!(p0_bool svbool_t "p0" "b" "z"); +#[cfg(target_feature = "sve")] +#[no_mangle] +pub unsafe fn p0_bool(inp: &svbool_t, pred: &svbool_t) -> svbool_t { + let x = *inp; + let z = *pred; + let y; + asm!("mov p0.b, p1/z, p0.b", in("p1") z, lateout("p0") y, in("p0") x); + y +} // CHECK-LABEL: {{("#)?}}v0_ptr{{"?}} // CHECK: //APP diff --git a/tests/ui/asm/aarch64/arm64ec-sve.rs b/tests/ui/asm/aarch64/arm64ec-sve.rs index 3af9beeb58213..05830aee8a974 100644 --- a/tests/ui/asm/aarch64/arm64ec-sve.rs +++ b/tests/ui/asm/aarch64/arm64ec-sve.rs @@ -17,8 +17,6 @@ fn f(x: f64) { unsafe { asm!("", out("p0") _); //~^ ERROR cannot use register `p0` - asm!("", out("z0") _); - //~^ ERROR cannot use register `z0` asm!("", out("ffr") _); //~^ ERROR cannot use register `ffr` } diff --git a/tests/ui/asm/aarch64/arm64ec-sve.stderr b/tests/ui/asm/aarch64/arm64ec-sve.stderr index 2ee8a0b6546e9..d654eb4ba1a19 100644 --- a/tests/ui/asm/aarch64/arm64ec-sve.stderr +++ b/tests/ui/asm/aarch64/arm64ec-sve.stderr @@ -1,20 +1,14 @@ -error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC +error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC --> $DIR/arm64ec-sve.rs:18:18 | LL | asm!("", out("p0") _); | ^^^^^^^^^^^ -error: cannot use register `z0`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC +error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC --> $DIR/arm64ec-sve.rs:20:18 | -LL | asm!("", out("z0") _); - | ^^^^^^^^^^^ - -error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, z*, p*, ffr cannot be used for Arm64EC - --> $DIR/arm64ec-sve.rs:22:18 - | LL | asm!("", out("ffr") _); | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index 95cd8a4331932..daaca4746cf37 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -38,12 +38,15 @@ fn main() { asm!("", in("x19") foo); //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm - asm!("", in("p0") foo); - //~^ ERROR type `i32` cannot be used with this register class - asm!("", out("p0") _); - asm!("{}", in(preg) foo); - //~^ ERROR type `i32` cannot be used with this register class - asm!("{}", out(preg) _); + asm!("", in("ffr") foo); + //~^ ERROR register class `ffr` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("ffr") _); + asm!("{}", in(ffr) foo); + //~^ ERROR register class `ffr` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class + asm!("{}", out(ffr) _); + //~^ ERROR register class `ffr` can only be used as a clobber, not as an input or output // Explicit register conflicts // (except in/lateout which don't conflict) diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index 4e54ee85fec8c..8937509763dec 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -4,7 +4,7 @@ error: invalid register class `foo`: unknown register class LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, `zreg`, and `preg` + = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, `preg`, and `ffr` error: invalid register `foo`: unknown register --> $DIR/bad-reg.rs:20:18 @@ -30,7 +30,7 @@ LL | asm!("{:r}", in(vreg) foo); | | | template modifier | - = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, and `v` + = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`, and `z` error: invalid asm template modifier `r` for this register class --> $DIR/bad-reg.rs:26:15 @@ -40,7 +40,7 @@ LL | asm!("{:r}", in(vreg_low16) foo); | | | template modifier | - = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, and `v` + = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`, and `z` error: asm template modifiers are not allowed for `const` arguments --> $DIR/bad-reg.rs:28:15 @@ -82,8 +82,26 @@ error: invalid register `x19`: x19 is used internally by LLVM and cannot be used LL | asm!("", in("x19") foo); | ^^^^^^^^^^^^^ +error: register class `ffr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:41:18 + | +LL | asm!("", in("ffr") foo); + | ^^^^^^^^^^^^^ + +error: register class `ffr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:45:20 + | +LL | asm!("{}", in(ffr) foo); + | ^^^^^^^^^^^ + +error: register class `ffr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:48:20 + | +LL | asm!("{}", out(ffr) _); + | ^^^^^^^^^^ + error: register `w0` conflicts with register `x0` - --> $DIR/bad-reg.rs:51:32 + --> $DIR/bad-reg.rs:54:32 | LL | asm!("", in("x0") foo, in("w0") bar); | ------------ ^^^^^^^^^^^^ register `w0` @@ -91,7 +109,7 @@ LL | asm!("", in("x0") foo, in("w0") bar); | register `x0` error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:53:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("", in("x0") foo, out("x0") bar); | ------------ ^^^^^^^^^^^^^ register `x0` @@ -99,13 +117,13 @@ LL | asm!("", in("x0") foo, out("x0") bar); | register `x0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:53:18 + --> $DIR/bad-reg.rs:56:18 | LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:56:32 + --> $DIR/bad-reg.rs:59:32 | LL | asm!("", in("v0") foo, in("q0") bar); | ------------ ^^^^^^^^^^^^ register `q0` @@ -113,7 +131,7 @@ LL | asm!("", in("v0") foo, in("q0") bar); | register `v0` error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:58:32 + --> $DIR/bad-reg.rs:61:32 | LL | asm!("", in("v0") foo, out("q0") bar); | ------------ ^^^^^^^^^^^^^ register `q0` @@ -121,26 +139,26 @@ LL | asm!("", in("v0") foo, out("q0") bar); | register `v0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:58:18 + --> $DIR/bad-reg.rs:61:18 | LL | asm!("", in("v0") foo, out("q0") bar); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:41:27 + --> $DIR/bad-reg.rs:41:28 | -LL | asm!("", in("p0") foo); - | ^^^ +LL | asm!("", in("ffr") foo); + | ^^^ | - = note: register class `preg` supports these types: svbool_t + = note: register class `ffr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:44:29 + --> $DIR/bad-reg.rs:45:28 | -LL | asm!("{}", in(preg) foo); - | ^^^ +LL | asm!("{}", in(ffr) foo); + | ^^^ | - = note: register class `preg` supports these types: svbool_t + = note: register class `ffr` supports these types: -error: aborting due to 17 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index 168257fa26119..2b87d242a6442 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -37,11 +37,12 @@ fn main() { asm!("{:d}", in(vreg) 0f64); asm!("{:q}", in(vreg) f64x2); asm!("{:v}", in(vreg) f64x2); - asm!("{:z}", in(zreg) svi32); - asm!("{:p}", in(preg) svb8); + asm!("{:z}", in(vreg) svi32); + asm!("{}", in(preg) svb8); // Should be the same as vreg asm!("{:q}", in(vreg_low16) f64x2); + asm!("{:z}", in(vreg_low16) svi32); // Template modifiers of a different size to the argument are fine asm!("{:w}", in(reg) 0u64); @@ -68,11 +69,11 @@ fn main() { //~^ WARN formatting may not be suitable for sub-register argument asm!("{}", in(vreg_low16) 0f64); //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(zreg) svi16); + asm!("{}", in(vreg) svi16); //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(zreg) svi32); + asm!("{}", in(vreg) svi32); //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(zreg) svf64); + asm!("{}", in(vreg) svf64); //~^ WARN formatting may not be suitable for sub-register argument asm!("{0} {0}", in(reg) 0i16); @@ -92,14 +93,10 @@ fn main() { //~^ ERROR type `svint32_t` cannot be used with this register class asm!("{}", in(reg) svb8); //~^ ERROR type `svbool_t` cannot be used with this register class - asm!("{}", in(vreg) svi32); - //~^ ERROR type `svint32_t` cannot be used with this register class asm!("{}", in(vreg) svb8); //~^ ERROR type `svbool_t` cannot be used with this register class asm!("{}", in(preg) svi32); //~^ ERROR type `svint32_t` cannot be used with this register class - asm!("{}", in(zreg) svb8); - //~^ ERROR type `svbool_t` cannot be used with this register class // Split inout operands must have compatible types let mut val_i16: i16; diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr index 2840049b83ab1..e407ed3a9d3ac 100644 --- a/tests/ui/asm/aarch64/type-check-3.stderr +++ b/tests/ui/asm/aarch64/type-check-3.stderr @@ -1,5 +1,5 @@ warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:54:15 + --> $DIR/type-check-3.rs:55:15 | LL | asm!("{}", in(reg) 0u8); | ^^ --- for this argument @@ -9,7 +9,7 @@ LL | asm!("{}", in(reg) 0u8); = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:56:15 + --> $DIR/type-check-3.rs:57:15 | LL | asm!("{}", in(reg) 0u16); | ^^ ---- for this argument @@ -18,7 +18,7 @@ LL | asm!("{}", in(reg) 0u16); = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:58:15 + --> $DIR/type-check-3.rs:59:15 | LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument @@ -27,7 +27,7 @@ LL | asm!("{}", in(reg) 0i32); = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:60:15 + --> $DIR/type-check-3.rs:61:15 | LL | asm!("{}", in(reg) 0f32); | ^^ ---- for this argument @@ -36,7 +36,7 @@ LL | asm!("{}", in(reg) 0f32); = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:63:15 + --> $DIR/type-check-3.rs:64:15 | LL | asm!("{}", in(vreg) 0i16); | ^^ ---- for this argument @@ -45,7 +45,7 @@ LL | asm!("{}", in(vreg) 0i16); = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:65:15 + --> $DIR/type-check-3.rs:66:15 | LL | asm!("{}", in(vreg) 0f32); | ^^ ---- for this argument @@ -54,7 +54,7 @@ LL | asm!("{}", in(vreg) 0f32); = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:67:15 + --> $DIR/type-check-3.rs:68:15 | LL | asm!("{}", in(vreg) 0f64); | ^^ ---- for this argument @@ -63,7 +63,7 @@ LL | asm!("{}", in(vreg) 0f64); = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:69:15 + --> $DIR/type-check-3.rs:70:15 | LL | asm!("{}", in(vreg_low16) 0f64); | ^^ ---- for this argument @@ -72,34 +72,34 @@ LL | asm!("{}", in(vreg_low16) 0f64); = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:71:15 + --> $DIR/type-check-3.rs:72:15 | -LL | asm!("{}", in(zreg) svi16); +LL | asm!("{}", in(vreg) svi16); | ^^ ----- for this argument | = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) - = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:73:15 + --> $DIR/type-check-3.rs:74:15 | -LL | asm!("{}", in(zreg) svi32); +LL | asm!("{}", in(vreg) svi32); | ^^ ----- for this argument | = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) - = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:75:15 + --> $DIR/type-check-3.rs:76:15 | -LL | asm!("{}", in(zreg) svf64); +LL | asm!("{}", in(vreg) svf64); | ^^ ----- for this argument | = help: use `{0:z}` to have the register formatted as `z0` (for scalable values) - = help: or use `{0:z}` to keep the default formatting of `z0` (for scalable values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 16-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:78:15 + --> $DIR/type-check-3.rs:79:15 | LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument @@ -108,7 +108,7 @@ LL | asm!("{0} {0}", in(reg) 0i16); = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:80:15 + --> $DIR/type-check-3.rs:81:15 | LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument @@ -117,7 +117,7 @@ LL | asm!("{0} {0:x}", in(reg) 0i16); = help: or use `{0:x}` to keep the default formatting of `x0` (for 8-byte values) error: type `i128` cannot be used with this register class - --> $DIR/type-check-3.rs:85:28 + --> $DIR/type-check-3.rs:86:28 | LL | asm!("{}", in(reg) 0i128); | ^^^^^ @@ -125,7 +125,7 @@ LL | asm!("{}", in(reg) 0i128); = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 error: type `float64x2_t` cannot be used with this register class - --> $DIR/type-check-3.rs:87:28 + --> $DIR/type-check-3.rs:88:28 | LL | asm!("{}", in(reg) f64x2); | ^^^^^ @@ -133,15 +133,15 @@ LL | asm!("{}", in(reg) f64x2); = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 error: type `Simd256bit` cannot be used with this register class - --> $DIR/type-check-3.rs:89:29 + --> $DIR/type-check-3.rs:90:29 | LL | asm!("{}", in(vreg) f64x4); | ^^^^^ | - = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2, svint8_t, svint16_t, svint32_t, svint64_t, svint128_t, svfloat26_t, svfloat32_t, svfloat64_t, svint128_t, svfloat128_t error: type `svint32_t` cannot be used with this register class - --> $DIR/type-check-3.rs:91:28 + --> $DIR/type-check-3.rs:92:28 | LL | asm!("{}", in(reg) svi32); | ^^^^^ @@ -149,47 +149,31 @@ LL | asm!("{}", in(reg) svi32); = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 error: type `svbool_t` cannot be used with this register class - --> $DIR/type-check-3.rs:93:28 + --> $DIR/type-check-3.rs:94:28 | LL | asm!("{}", in(reg) svb8); | ^^^^ | = note: register class `reg` supports these types: i8, i16, i32, i64, f16, f32, f64 -error: type `svint32_t` cannot be used with this register class - --> $DIR/type-check-3.rs:95:29 - | -LL | asm!("{}", in(vreg) svi32); - | ^^^^^ - | - = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 - error: type `svbool_t` cannot be used with this register class - --> $DIR/type-check-3.rs:97:29 + --> $DIR/type-check-3.rs:96:29 | LL | asm!("{}", in(vreg) svb8); | ^^^^ | - = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + = note: register class `vreg` supports these types: i8, i16, i32, i64, f16, f32, f64, f128, i8x8, i16x4, i32x2, i64x1, f16x4, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2, svint8_t, svint16_t, svint32_t, svint64_t, svint128_t, svfloat26_t, svfloat32_t, svfloat64_t, svint128_t, svfloat128_t error: type `svint32_t` cannot be used with this register class - --> $DIR/type-check-3.rs:99:29 + --> $DIR/type-check-3.rs:98:29 | LL | asm!("{}", in(preg) svi32); | ^^^^^ | = note: register class `preg` supports these types: svbool_t -error: type `svbool_t` cannot be used with this register class - --> $DIR/type-check-3.rs:101:29 - | -LL | asm!("{}", in(zreg) svb8); - | ^^^^ - | - = note: register class `zreg` supports these types: svint8_t, svint16_t, svint32_t, svint64_t, svint128_t, svfloat26_t, svfloat32_t, svfloat64_t, svint128_t, svfloat128_t - error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:111:33 + --> $DIR/type-check-3.rs:108:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_f32); | ^^^^ ^^^^^^^ type `f32` @@ -199,7 +183,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_f32); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:113:33 + --> $DIR/type-check-3.rs:110:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); | ^^^^ ^^^^^^^ type `*mut u8` @@ -209,7 +193,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:115:33 + --> $DIR/type-check-3.rs:112:33 | LL | asm!("{:x}", inout(reg) main => val_u32); | ^^^^ ^^^^^^^ type `u32` @@ -218,5 +202,5 @@ LL | asm!("{:x}", inout(reg) main => val_u32); | = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size -error: aborting due to 12 previous errors; 13 warnings emitted +error: aborting due to 10 previous errors; 13 warnings emitted From c91f5cb687b96623ef2da025bcf1a0ac7fa0c3ab Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 25 Aug 2026 19:30:05 +0100 Subject: [PATCH 32/40] Gate asm support for SVE under asm_experimental_reg --- compiler/rustc_target/src/asm/aarch64.rs | 37 +++++++++---- compiler/rustc_target/src/asm/mod.rs | 2 +- .../language-features/asm-experimental-reg.md | 4 ++ tests/assembly-llvm/asm/aarch64-types.rs | 2 +- tests/ui/asm/aarch64/type-check-3.rs | 2 +- ...e-gate-asm_experimental_reg.aarch64.stderr | 53 +++++++++++++++++++ ...ate-asm_experimental_reg.loongarch.stderr} | 8 +-- .../feature-gate-asm_experimental_reg.rs | 51 +++++++++++++++--- 8 files changed, 136 insertions(+), 23 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-asm_experimental_reg.aarch64.stderr rename tests/ui/feature-gates/{feature-gate-asm_experimental_reg.stderr => feature-gate-asm_experimental_reg.loongarch.stderr} (90%) diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 39dfd6c3bb070..83d249262c104 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -62,19 +62,36 @@ impl AArch64InlineAsmRegClass { pub fn supported_types( self, _arch: InlineAsmArch, + allow_experimental_reg: bool, ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg => types! { _: I8, I16, I32, I64, F16, F32, F64; }, - Self::vreg | Self::vreg_low16 => types! { - neon: I8, I16, I32, I64, F16, F32, F64, F128, - VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1), - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - sve: SveVecI8, SveVecI16, SveVecI32, SveVecI64, SveVecI128, SveVecF16, SveVecF32, - SveVecF64, SveVecI128, SveVecF128; - }, - Self::preg => types! { - sve: SveVecBool; - }, + Self::vreg | Self::vreg_low16 => { + if allow_experimental_reg { + types! { + neon: I8, I16, I32, I64, F16, F32, F64, F128, + VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1), + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); + sve: SveVecI8, SveVecI16, SveVecI32, SveVecI64, SveVecI128, SveVecF16, SveVecF32, + SveVecF64, SveVecI128, SveVecF128; + } + } else { + types! { + neon: I8, I16, I32, I64, F16, F32, F64, F128, + VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1), + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); + } + } + } + Self::preg => { + if allow_experimental_reg { + types! { + sve: SveVecBool; + } + } else { + &[] + } + } Self::ffr => &[], } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index c0ed24065180b..6f9751e807490 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -648,7 +648,7 @@ impl InlineAsmRegClass { match self { Self::X86(r) => r.supported_types(arch, allow_experimental_reg).into(), Self::Arm(r) => r.supported_types(arch).into(), - Self::AArch64(r) => r.supported_types(arch).into(), + Self::AArch64(r) => r.supported_types(arch, allow_experimental_reg).into(), Self::Amdgpu(r) => r.supported_types(arch).into(), Self::RiscV(r) => r.supported_types(arch).into(), Self::Nvptx(r) => r.supported_types(arch).into(), diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md index 854d66f96756c..89e82126ece3a 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md @@ -14,6 +14,7 @@ This tracks support for additional registers in architectures where inline assem | ------------ | -------------- | --------- | -------------------- | | LoongArch | `vreg` | `$vr[0-31]` | `f` | | LoongArch | `xreg` | `$xr[0-31]` | `f` | +| AArch64 | `preg` | `p[0-16]` | `Upa` | ## Register class supported types @@ -21,6 +22,8 @@ This tracks support for additional registers in architectures where inline assem | ------------ | -------------- | -------------- | ------------- | | LoongArch | `vreg` | `lsx` | `i128`, `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | LoongArch | `xreg` | `lasx` | `i128`, `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`,
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` | +| AArch64 | `vreg` | `sve` | `i8xN`, `i16xB`, `i32xN`, `i64xN`, `f16xN`, `f32xN`, `f64xN` (scalable vector) | +| AArch64 | `preg` | `sve` | `i1xN` (scalable vector predicate) | ## Register aliases @@ -45,3 +48,4 @@ This tracks support for additional registers in architectures where inline assem | LoongArch | `vreg` | `u` | `$xr0` | `u` | | LoongArch | `xreg` | None | `$xr0` | `u` | | LoongArch | `xreg` | `w` | `$vr0` | `w` | +| AArch64 | `vreg` | `z` | `z0` | `z` | diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs index 64a54a208ba54..da625b1211602 100644 --- a/tests/assembly-llvm/asm/aarch64-types.rs +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -9,7 +9,7 @@ //@ [arm64ec] needs-llvm-components: aarch64 //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, f16, f128, rustc_attrs)] +#![feature(asm_experimental_reg, no_core, f16, f128, rustc_attrs)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index 2b87d242a6442..6c01a3380f169 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -1,7 +1,7 @@ //@ only-aarch64 //@ compile-flags: -C target-feature=+neon,+sve -#![feature(repr_simd, stdarch_aarch64_sve)] +#![feature(asm_experimental_reg, repr_simd, stdarch_aarch64_sve)] use std::arch::aarch64::{float64x2_t, svdup_n_f64, svdup_n_s16, svdup_n_s32, svptrue_b8}; use std::arch::{asm, global_asm}; diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.aarch64.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.aarch64.stderr new file mode 100644 index 0000000000000..f19cb17a04a29 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.aarch64.stderr @@ -0,0 +1,53 @@ +error[E0658]: register class `preg` can only be used as a clobber in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:45:23 + | +LL | asm!("/* {0} */", in(preg) p); + | ^^^^^^^^^^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `svint32_t` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:33:32 + | +LL | asm!("/* {0} */", in(vreg) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `svint32_t` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:36:38 + | +LL | asm!("/* {0} */", in(vreg_low16) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `svint32_t` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:39:23 + | +LL | asm!("", in("z0") x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `svbool_t` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:45:32 + | +LL | asm!("/* {0} */", in(preg) p); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.loongarch.stderr similarity index 90% rename from tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr rename to tests/ui/feature-gates/feature-gate-asm_experimental_reg.loongarch.stderr index fb54438ef589e..0f829dd65cb47 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.loongarch.stderr @@ -1,5 +1,5 @@ error[E0658]: register class `vreg` can only be used as a clobber in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:21:41 + --> $DIR/feature-gate-asm_experimental_reg.rs:60:41 | LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); | ^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: register class `vreg` can only be used as a clobber in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:21:54 + --> $DIR/feature-gate-asm_experimental_reg.rs:60:54 | LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: type `i8x16` cannot be used with this register class in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:21:51 + --> $DIR/feature-gate-asm_experimental_reg.rs:60:51 | LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); | ^ @@ -29,7 +29,7 @@ LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: type `i8x16` cannot be used with this register class in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:21:63 + --> $DIR/feature-gate-asm_experimental_reg.rs:60:63 | LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); | ^ diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs index 0d2c4fe2b67c3..c91036366a028 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs @@ -1,6 +1,9 @@ //@ add-minicore -//@ compile-flags: --target loongarch64-unknown-none -//@ needs-llvm-components: loongarch +//@ revisions: aarch64 loongarch +//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+sve +//@ [aarch64] needs-llvm-components: aarch64 +//@ [loongarch] compile-flags: --target loongarch64-unknown-none +//@ [loongarch] needs-llvm-components: loongarch //@ ignore-backends: gcc #![feature(no_core, lang_items, rustc_attrs, repr_simd)] @@ -11,17 +14,53 @@ extern crate minicore; use minicore::*; +#[cfg(aarch64)] +#[rustc_scalable_vector(4)] +pub struct svint32_t(i32); + +#[cfg(aarch64)] +impl Copy for svint32_t {} + +#[cfg(aarch64)] +#[rustc_scalable_vector(16)] +pub struct svbool_t(bool); + +#[cfg(aarch64)] +impl Copy for svbool_t {} + +#[cfg(aarch64)] +unsafe fn vector(x: svint32_t) { + asm!("/* {0} */", in(vreg) x); + //[aarch64]~^ ERROR type `svint32_t` cannot be used with this register class in stable + + asm!("/* {0} */", in(vreg_low16) x); + //[aarch64]~^ ERROR type `svint32_t` cannot be used with this register class in stable + + asm!("", in("z0") x); + //[aarch64]~^ ERROR type `svint32_t` cannot be used with this register class in stable +} + +#[cfg(aarch64)] +unsafe fn predicate(p: svbool_t) { + asm!("/* {0} */", in(preg) p); + //[aarch64]~^ ERROR register class `preg` can only be used as a clobber in stable + //[aarch64]~| ERROR type `svbool_t` cannot be used with this register class in stable +} + +#[cfg(loongarch)] #[repr(simd)] pub struct i8x16([i8; 16]); +#[cfg(loongarch)] impl Copy for i8x16 {} +#[cfg(loongarch)] unsafe fn main(x: i8x16) -> i8x16 { let y; asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); - //~^ ERROR register class `vreg` can only be used as a clobber in stable - //~| ERROR register class `vreg` can only be used as a clobber in stable - //~| ERROR type `i8x16` cannot be used with this register class in stable - //~| ERROR type `i8x16` cannot be used with this register class in stable + //[loongarch]~^ ERROR register class `vreg` can only be used as a clobber in stable + //[loongarch]~| ERROR register class `vreg` can only be used as a clobber in stable + //[loongarch]~| ERROR type `i8x16` cannot be used with this register class in stable + //[loongarch]~| ERROR type `i8x16` cannot be used with this register class in stable y } From a305a9c3b6f2ff0a9833dc69f26ea6c8602b5ed9 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 20 Aug 2026 13:13:06 +0200 Subject: [PATCH 33/40] fix `is_homogeneous_aggregate`: use unit size, not total size --- .../src/mono_checks/abi_check.rs | 10 +- compiler/rustc_target/src/callconv/aarch64.rs | 2 +- compiler/rustc_target/src/callconv/arm.rs | 2 +- .../rustc_target/src/callconv/powerpc64.rs | 2 +- tests/auxiliary/minicore.rs | 1 + .../aarch64-abi/homogeneous-aggregate.rs | 84 ++++++++++++++++ .../arm-abi/homogeneous-aggregate.rs | 65 +++++++++++++ .../powerpc64-abi/homogeneous-aggregate.rs | 96 +++++++++++++++++++ .../preserve-vec-element-types.rs | 27 +++--- 9 files changed, 272 insertions(+), 17 deletions(-) create mode 100644 tests/codegen-llvm/aarch64-abi/homogeneous-aggregate.rs create mode 100644 tests/codegen-llvm/powerpc64-abi/homogeneous-aggregate.rs diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 7e5ea6bf3c22c..885ad6071d91c 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -65,9 +65,17 @@ fn do_check_simd_vector_abi<'tcx>( let size = arg_abi.layout.size; match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) { UsesVectorRegisters::FixedVector => { + // Some targets use homogeneous aggregates, where the unit size counts. + let unit_size = match &arg_abi.mode { + PassMode::Cast { pad_i32_count: _, cast } if cast.prefix.is_empty() => { + cast.rest.unit.size + } + _ => size, + }; + let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi(); // Find the first feature that provides at least this vector size. - let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + let feature = match feature_def.iter().find(|(bits, _)| unit_size.bits() <= *bits) { Some((_, feature)) => feature, None => { let (span, _hir_id) = loc(); diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 0162aa838cb6b..09187836ee65a 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -35,7 +35,7 @@ where // The softfloat ABI treats floats like integers, so they // do not get homogeneous aggregate treatment. RegKind::Float => cx.target_spec().rustc_abi != Some(RustcAbi::Softfloat), - RegKind::Vector { .. } => size.bits() == 64 || size.bits() == 128, + RegKind::Vector { .. } => unit.size.bits() == 64 || unit.size.bits() == 128, }; valid_unit.then_some(Uniform::consecutive(unit, size)) diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 66f0ded3874f9..615bd4f540068 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -26,7 +26,7 @@ where let valid_unit = match unit.kind { RegKind::Integer => false, RegKind::Float => true, - RegKind::Vector { .. } => size.bits() == 64 || size.bits() == 128, + RegKind::Vector { .. } => unit.size.bits() == 64 || unit.size.bits() == 128, }; valid_unit.then_some(Uniform::consecutive(unit, size)) diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 3eb40abe90f33..075e69f7d74d8 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -36,7 +36,7 @@ where let valid_unit = match unit.kind { RegKind::Integer => false, RegKind::Float => true, - RegKind::Vector { .. } => arg.layout.size.bits() == 128, + RegKind::Vector { .. } => unit.size.bits() == 128, }; valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size)) diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 04564049dbed2..2b7eb0b9afbcf 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -496,4 +496,5 @@ pub mod simd { pub type i64x8 = Simd; pub type u8x16 = Simd; + pub type u64x2 = Simd; } diff --git a/tests/codegen-llvm/aarch64-abi/homogeneous-aggregate.rs b/tests/codegen-llvm/aarch64-abi/homogeneous-aggregate.rs new file mode 100644 index 0000000000000..3d5ec10f2b2f7 --- /dev/null +++ b/tests/codegen-llvm/aarch64-abi/homogeneous-aggregate.rs @@ -0,0 +1,84 @@ +//@ add-minicore +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 +// +//@ revisions: linux win +//@[linux] compile-flags: --target aarch64-unknown-linux-gnu +//@[win] compile-flags: --target aarch64-pc-windows-msvc +// +//@ needs-llvm-components: aarch64 + +// Test that homogeneous aggregates are passed and returned with the correct ABI. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::simd::*; +use minicore::*; + +// A homogeneous float aggregate. +#[repr(C)] +pub struct Hfa { + pub a: f32, + pub b: f32, +} +impl Copy for Hfa {} + +// CHECK: define void @test_hfa([2 x float] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa(a: Hfa) { + hint::black_box(a); +} + +// Fields can be vectors too. +#[repr(C)] +pub struct Hfa2V2F64 { + pub a: f64x2, + pub b: f64x2, +} + +// CHECK: define void @test_hfa_2_f64x2([2 x <2 x double>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_f64x2(a: Hfa2V2F64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2U64 { + pub a: u64x2, + pub b: u64x2, +} + +// CHECK: define void @test_hfa_2_u64x2([2 x <16 x i8>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_u64x2(a: Hfa2V2U64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2F32 { + pub a: f32x2, + pub b: f32x2, +} + +// CHECK: define void @test_hfa_2_f32x2([2 x <2 x float>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_f32x2(a: Hfa2V2F32) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa4V2F64 { + pub a: f64x2, + pub b: f64x2, + pub c: f64x2, + pub d: f64x2, +} + +// CHECK: define void @test_hfa_4_f64x2([4 x <2 x double>] %0) +#[unsafe(no_mangle)] +#[target_feature(enable = "neon")] +pub extern "C" fn test_hfa_4_f64x2(a: Hfa4V2F64) { + hint::black_box(a); +} diff --git a/tests/codegen-llvm/arm-abi/homogeneous-aggregate.rs b/tests/codegen-llvm/arm-abi/homogeneous-aggregate.rs index c44dc4fa56f5f..272eb419494b0 100644 --- a/tests/codegen-llvm/arm-abi/homogeneous-aggregate.rs +++ b/tests/codegen-llvm/arm-abi/homogeneous-aggregate.rs @@ -11,10 +11,12 @@ // Test that homogeneous aggregates are passed and returned with the correct ABI on 32-bit arm. #![feature(no_core, lang_items)] +#![feature(arm_target_feature)] #![crate_type = "lib"] #![no_core] extern crate minicore; +use minicore::simd::*; use minicore::*; // A homogeneous float aggregate, which a hard-float ABI passes in VFP registers. @@ -68,6 +70,69 @@ pub extern "C" fn test_hfa_4_f64(a: Hfa4F64) { hint::black_box(a); } +// Fields can be vectors too. +#[repr(C)] +pub struct Hfa2V2F64 { + pub a: f64x2, + pub b: f64x2, +} + +// linux: define void @test_hfa_2_f64x2([2 x <2 x double>] %0) +// eabi: define dso_local void @test_hfa_2_f64x2([4 x i64] %0) +// watchos: define void @test_hfa_2_f64x2([2 x <2 x double>] %0) +#[unsafe(no_mangle)] +#[target_feature(enable = "neon")] +pub extern "C" fn test_hfa_2_f64x2(a: Hfa2V2F64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2U64 { + pub a: u64x2, + pub b: u64x2, +} + +// linux: define void @test_hfa_2_u64x2([2 x <16 x i8>] %0) +// eabi: define dso_local void @test_hfa_2_u64x2([4 x i64] %0) +// watchos: define void @test_hfa_2_u64x2([2 x <16 x i8>] %0) +#[unsafe(no_mangle)] +#[target_feature(enable = "neon")] +pub extern "C" fn test_hfa_2_u64x2(a: Hfa2V2U64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2F32 { + pub a: f32x2, + pub b: f32x2, +} + +// linux: define void @test_hfa_2_f32x2([2 x <2 x float>] %0) +// eabi: define dso_local void @test_hfa_2_f32x2([2 x i64] %0) +// watchos: define void @test_hfa_2_f32x2([2 x <2 x float>] %0) +#[unsafe(no_mangle)] +#[target_feature(enable = "neon")] +pub extern "C" fn test_hfa_2_f32x2(a: Hfa2V2F32) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa4V2F64 { + pub a: f64x2, + pub b: f64x2, + pub c: f64x2, + pub d: f64x2, +} + +// linux: define void @test_hfa_4_f64x2([4 x <2 x double>] %0) +// eabi: define dso_local void @test_hfa_4_f64x2([8 x i64] %0) +// watchos: define void @test_hfa_4_f64x2([4 x <2 x double>] %0) +#[unsafe(no_mangle)] +#[target_feature(enable = "neon")] +pub extern "C" fn test_hfa_4_f64x2(a: Hfa4V2F64) { + hint::black_box(a); +} + // A homogeneous aggregate can have at most 4 fields, so this does not qualify. #[repr(C)] pub struct Floats5 { diff --git a/tests/codegen-llvm/powerpc64-abi/homogeneous-aggregate.rs b/tests/codegen-llvm/powerpc64-abi/homogeneous-aggregate.rs new file mode 100644 index 0000000000000..dd053411aa4e5 --- /dev/null +++ b/tests/codegen-llvm/powerpc64-abi/homogeneous-aggregate.rs @@ -0,0 +1,96 @@ +//@ add-minicore +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 +// +//@ revisions: ppc64 ppc64_vsx ppc64le +//@[ppc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[ppc64_vsx] compile-flags: --target powerpc64-unknown-linux-gnu -Ctarget-feature=+vsx +//@[ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu +// +//@ needs-llvm-components: powerpc + +// Test that homogeneous aggregates are passed and returned with the correct ABI. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::simd::*; +use minicore::*; + +// A homogeneous float aggregate. +#[repr(C)] +pub struct Hfa { + pub a: f32, + pub b: f32, +} +impl Copy for Hfa {} + +// ppc64: define void @test_hfa(i64 %0) +// ppc64_vsx: define void @test_hfa(i64 %0) +// ppc64le: define void @test_hfa([2 x float] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa(a: Hfa) { + hint::black_box(a); +} + +// Fields can be vectors too. +#[repr(C)] +pub struct Hfa2V2F64 { + pub a: f64x2, + pub b: f64x2, +} + +// ppc64: define void @test_hfa_2_f64x2([2 x i128] %0) +// ppc64_vsx: define void @test_hfa_2_f64x2([2 x i128] %0) +// ppc64le: define void @test_hfa_2_f64x2([2 x <2 x double>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_f64x2(a: Hfa2V2F64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2U64 { + pub a: u64x2, + pub b: u64x2, +} + +// ppc64: define void @test_hfa_2_u64x2([2 x i128] %0) +// ppc64_vsx: define void @test_hfa_2_u64x2([2 x i128] %0) +// ppc64le: define void @test_hfa_2_u64x2([2 x <16 x i8>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_u64x2(a: Hfa2V2U64) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa2V2F32 { + pub a: f32x2, + pub b: f32x2, +} + +// On PowerPC only 128-bit units are eligible for HVA. +// +// ppc64: define void @test_hfa_2_f32x2([2 x i64] %0) +// ppc64_vsx: define void @test_hfa_2_f32x2([2 x i64] %0) +// ppc64le: define void @test_hfa_2_f32x2([2 x i64] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_2_f32x2(a: Hfa2V2F32) { + hint::black_box(a); +} + +#[repr(C)] +pub struct Hfa4V2F64 { + pub a: f64x2, + pub b: f64x2, + pub c: f64x2, + pub d: f64x2, +} + +// ppc64: define void @test_hfa_4_f64x2([4 x i128] %0) +// ppc64_vsx: define void @test_hfa_4_f64x2([4 x i128] %0) +// ppc64le: define void @test_hfa_4_f64x2([4 x <2 x double>] %0) +#[unsafe(no_mangle)] +pub extern "C" fn test_hfa_4_f64x2(a: Hfa4V2F64) { + hint::black_box(a); +} diff --git a/tests/codegen-llvm/preserve-vec-element-types.rs b/tests/codegen-llvm/preserve-vec-element-types.rs index b3908b1c24cc2..00f9ef6fab2a6 100644 --- a/tests/codegen-llvm/preserve-vec-element-types.rs +++ b/tests/codegen-llvm/preserve-vec-element-types.rs @@ -52,21 +52,22 @@ mod tests { // CHECK: define [2 x <1 x ptr>] @pair_ptrx1_t([2 x <1 x ptr>] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn pair_ptrx1_t(x: Pair>) -> Pair> { x } - // When it fits in a 128-bit register, it's passed directly. + // When the fields are not 64 or 128 bits in size, they do not qualify as a homogeneous + // aggregate, and passed as type-erased sequences of integers. - // CHECK: define [4 x <4 x i8>] @quad_int8x4_t([4 x <4 x i8>] {{.*}} %0) + // CHECK: define [2 x i64] @quad_int8x4_t([2 x i64] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn quad_int8x4_t(x: Quad>) -> Quad> { x } - // CHECK: define [4 x <2 x i16>] @quad_int16x2_t([4 x <2 x i16>] {{.*}} %0) + // CHECK: define [2 x i64] @quad_int16x2_t([2 x i64] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn quad_int16x2_t(x: Quad>) -> Quad> { x } - // CHECK: define [4 x <1 x i32>] @quad_int32x1_t([4 x <1 x i32>] {{.*}} %0) + // CHECK: define [2 x i64] @quad_int32x1_t([2 x i64] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn quad_int32x1_t(x: Quad>) -> Quad> { x } - // CHECK: define [4 x <2 x half>] @quad_float16x2_t([4 x <2 x half>] {{.*}} %0) + // CHECK: define [2 x i64] @quad_float16x2_t([2 x i64] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn quad_float16x2_t(x: Quad>) -> Quad> { x } - // CHECK: define [4 x <1 x float>] @quad_float32x1_t([4 x <1 x float>] {{.*}} %0) + // CHECK: define [2 x i64] @quad_float32x1_t([2 x i64] {{.*}} %0) #[unsafe(no_mangle)] extern "C" fn quad_float32x1_t(x: Quad>) -> Quad> { x } // When it doesn't quite fit, padding is added which does erase the type. @@ -74,23 +75,23 @@ mod tests { // CHECK: define [2 x i64] @triple_int8x4_t #[unsafe(no_mangle)] extern "C" fn triple_int8x4_t(x: Triple>) -> Triple> { x } - // Other configurations are not passed by-value but indirectly. + // Other configurations passed directly when they qualify as a homogeneous aggregate. - // CHECK: define void @pair_int128x1_t + // CHECK: define [2 x <1 x i128>] @pair_int128x1_t([2 x <1 x i128>] #[unsafe(no_mangle)] extern "C" fn pair_int128x1_t(x: Pair>) -> Pair> { x } - // CHECK: define void @pair_float128x1_t + // CHECK: define [2 x <1 x fp128>] @pair_float128x1_t([2 x <1 x fp128>] #[unsafe(no_mangle)] extern "C" fn pair_float128x1_t(x: Pair>) -> Pair> { x } - // CHECK: define void @pair_int8x16_t + // CHECK: define [2 x <16 x i8>] @pair_int8x16_t([2 x <16 x i8>] #[unsafe(no_mangle)] extern "C" fn pair_int8x16_t(x: Pair>) -> Pair> { x } - // CHECK: define void @pair_int16x8_t + // CHECK: define [2 x <8 x i16>] @pair_int16x8_t([2 x <8 x i16>] #[unsafe(no_mangle)] extern "C" fn pair_int16x8_t(x: Pair>) -> Pair> { x } - // CHECK: define void @triple_int16x8_t + // CHECK: define [3 x <8 x i16>] @triple_int16x8_t([3 x <8 x i16>] #[unsafe(no_mangle)] extern "C" fn triple_int16x8_t(x: Triple>) -> Triple> { x } - // CHECK: define void @quad_int16x8_t + // CHECK: define [4 x <8 x i16>] @quad_int16x8_t([4 x <8 x i16>] #[unsafe(no_mangle)] extern "C" fn quad_int16x8_t(x: Quad>) -> Quad> { x } } From e7c3734a6a8d0e1f0e9de055c91ea008372beaf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 16:47:00 +0200 Subject: [PATCH 34/40] make closure-like types act like MaybeDangling --- compiler/rustc_codegen_ssa/src/mir/retag.rs | 2 +- .../src/interpret/validity.rs | 14 ++-- compiler/rustc_middle/src/ty/adt.rs | 8 +- compiler/rustc_middle/src/ty/layout.rs | 29 +++---- compiler/rustc_middle/src/ty/sty.rs | 13 ++- .../fail/async-shared-mutable.stack.stderr | 8 +- .../fail/async-shared-mutable.tree.stderr | 8 +- .../maybe_dangling_unalighed.stderr | 2 +- .../fail/validity/maybe_dangling_null.stderr | 2 +- .../maybe_dangling_ref_too_big.stderr | 2 +- .../tests/pass/both_borrows/maybe_dangling.rs | 14 ++++ src/tools/miri/tests/pass/generators.rs | 80 +++++++++++++++++++ tests/codegen-llvm/maybe_dangling_refs.rs | 8 +- 13 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 src/tools/miri/tests/pass/generators.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/retag.rs b/compiler/rustc_codegen_ssa/src/mir/retag.rs index 397fb423e8da3..a71a57f02c82a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/retag.rs +++ b/compiler/rustc_codegen_ssa/src/mir/retag.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx, V> RetagPlan { // the outermost `Box` is what determines the permission that gets created. ty::Adt(adt, _) if adt.is_box() => Self::visit_box(bx, layout, is_fn_entry), // Skip traversing for everything inside of `MaybeDangling` - ty::Adt(adt, _) if adt.is_maybe_dangling() => None, + _ if layout.ty.is_like_maybe_dangling() => None, _ => Self::walk_value(bx, layout, is_fn_entry), } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 2cd4caf5ba250..f388bb80b13ce 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -7,7 +7,6 @@ use std::borrow::Cow; use std::fmt::{self, Write}; use std::hash::Hash; -use std::mem; use std::num::NonZero; use either::{Left, Right}; @@ -1528,15 +1527,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, BackendRepr::Memory { .. } => unreachable!() } } - ty::Adt(adt, _) if adt.is_maybe_dangling() => { - let old_may_dangle = mem::replace(&mut self.may_dangle, true); - - let inner = self.ecx.project_field(val, FieldIdx::ZERO)?; - self.visit_value(&inner)?; - - self.may_dangle = old_may_dangle; - } _ => { + let old_may_dangle = self.may_dangle; + self.may_dangle |= val.layout.ty.is_like_maybe_dangling(); + // default handler try_validation!( self.walk_value(val), @@ -1546,6 +1540,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => InvalidMetaWrongTrait { expected_dyn_type, vtable_dyn_type }, ); + + self.may_dangle = old_may_dangle; } } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 0eea804b7cb53..af25d881f53bd 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -65,6 +65,8 @@ bitflags::bitflags! { /// Indicates whether the type is `FieldRepresentingType`. const IS_FIELD_REPRESENTING_TYPE = 1 << 13; /// Indicates whether the type is `MaybeDangling<_>`. + /// Note that this is not the only type with "maybe dangling" semantics! + /// Use `ty.is_like_maybe_dangling()` to check for that. const IS_MAYBE_DANGLING = 1 << 14; } } @@ -528,12 +530,6 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } - /// Returns `true` if this is `MaybeDangling`. - #[inline] - pub fn is_maybe_dangling(self) -> bool { - self.flags().contains(AdtFlags::IS_MAYBE_DANGLING) - } - /// Returns `true` if this is `Pin`. #[inline] pub fn is_pin(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 764f3b5b93318..c18bf81121377 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1090,20 +1090,6 @@ where }) } - ty::Adt(adt_def, ..) if adt_def.is_maybe_dangling() => { - Self::ty_and_layout_pointee_info_at(this.field(cx, 0), cx, offset).map(|info| { - PointeeInfo { - // Mark the pointer as raw - // (thus removing noalias/readonly/etc in case of the llvm backend) - safe: None, - // Make sure we don't assert dereferenceability of the pointer. - size: Size::ZERO, - // Preserve the alignment assertion! That is required even inside `MaybeDangling`. - align: info.align, - } - }) - } - _ => { let mut data_variant = match &this.variants { // Within the discriminant field, only the niche itself is @@ -1179,6 +1165,21 @@ where } } + // Patch result if we are a MaybeDangling-like type. + if this.ty.is_like_maybe_dangling() + && let Some(info) = result + { + result = Some(PointeeInfo { + // Mark the pointer as raw + // (thus removing noalias/readonly/etc in case of the llvm backend) + safe: None, + // Make sure we don't assert dereferenceability of the pointer. + size: Size::ZERO, + // Preserve the alignment assertion! That is required even inside `MaybeDangling`. + align: info.align, + }); + } + result } }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 013064b5cec4b..245289a0bc6cc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -23,7 +23,7 @@ use rustc_type_ir::{ use tracing::instrument; use ty::util::IntTypeExt; -use super::GenericParamDefKind; +use super::{AdtFlags, GenericParamDefKind}; use crate::infer::canonical::Canonical; use crate::traits::ObligationCause; use crate::ty::InferTy::*; @@ -2183,6 +2183,17 @@ impl<'tcx> Ty<'tcx> { pub fn walk(self) -> TypeWalker> { TypeWalker::new(self.into()) } + + /// Returns `true` if this is a `MaybeDangling`-like type, i.e., a type whose inner + /// references are not required to be dereferenceable and are not reborrowed. + #[inline] + pub fn is_like_maybe_dangling(self) -> bool { + match self.kind() { + ty::Adt(def, _) => def.flags().contains(AdtFlags::IS_MAYBE_DANGLING), + ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) => true, + _ => false, + } + } } impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List> { diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr index bdd004d5da99f..4435541bc0a1c 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr @@ -9,12 +9,8 @@ LL | *x = 1; help: was created by a Unique retag at offsets [RANGE] --> tests/fail/async-shared-mutable.rs:LL:CC | -LL | / core::future::poll_fn(move |_| { -LL | | *x = 1; -LL | | Poll::<()>::Pending -LL | | }) -LL | | .await - | |______________^ +LL | let x = &mut 0u8; + | ^^^^^^^^ help: was later invalidated at offsets [RANGE] by a SharedReadOnly retag --> tests/fail/async-shared-mutable.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index f9e75082758dd..bbb62a7e27b2b 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -10,12 +10,8 @@ LL | *x = 1; help: the accessed tag was created here, in the initial state Reserved --> tests/fail/async-shared-mutable.rs:LL:CC | -LL | / core::future::poll_fn(move |_| { -LL | | *x = 1; -LL | | Poll::<()>::Pending -LL | | }) -LL | | .await - | |______________^ +LL | let x = &mut 0u8; + | ^^^^^^^^ help: the accessed tag later transitioned to Unique due to a child write access at offsets [RANGE] --> tests/fail/async-shared-mutable.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr index 190976c4f046f..594c91352d796 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: at .0, encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs:LL:CC | LL | transmute::, MaybeDangling<&u16>>(unaligned) diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr index 041a6b1b96e0c..da8c88e16a1fe 100644 --- a/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: encountered a null reference +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: at .0, encountered a null reference --> tests/fail/validity/maybe_dangling_null.rs:LL:CC | LL | unsafe { transmute::, MaybeDangling<&u8>>(null) }; diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr index f0966586d4dc7..2c82b2719e711 100644 --- a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: encountered a reference that is too close to the end of the address space for a pointee of 1 bytes +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: at .0, encountered a reference that is too close to the end of the address space for a pointee of 1 bytes --> tests/fail/validity/maybe_dangling_ref_too_big.rs:LL:CC | LL | let _x: MaybeDangling<&i8> = unsafe { transmute(usize::MAX) }; diff --git a/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs index 028dcef8fa2d3..2d37344d24072 100644 --- a/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs +++ b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs @@ -14,6 +14,7 @@ fn main() { reference(); write_through_shared_ref(); large(); + closure(); } fn boxy() { @@ -64,3 +65,16 @@ fn large() { // Used to be rejected due to faulty logic for the "does this fit the address space" check. let _x: MaybeDangling<&i8> = unsafe { mem::transmute(usize::MAX - 127) }; } + +// A closure acts like MaybeDangling. +fn closure() { + fn invoke(f: impl FnOnce()) { + // The closure has captured a reference that will be freed while `invoke` runs. + f() + } + + let p = Box::leak(Box::new(0i32)); + invoke(move || { + drop(unsafe { Box::from_raw(p) }); + }); +} diff --git a/src/tools/miri/tests/pass/generators.rs b/src/tools/miri/tests/pass/generators.rs new file mode 100644 index 0000000000000..67a169bcfe821 --- /dev/null +++ b/src/tools/miri/tests/pass/generators.rs @@ -0,0 +1,80 @@ +//@edition: 2024 +#![feature(gen_blocks)] + +fn main() { + basic(); + iterate(); + movable_gen(); +} + +fn basic() { + gen fn foo() -> i32 { + yield 42; + for i in 5..10 { + if i % 2 == 0 { + continue; + } + yield i * 2; + } + } + + let v = foo().collect::>(); + assert_eq!(v, &[42, 10, 14, 18]); +} + +fn iterate() { + fn foo() -> impl Iterator { + gen { + yield 42; + for x in 3..6 { + yield x + } + } + } + + fn moved() -> impl Iterator { + let mut x = "foo".to_string(); + gen move { + yield 42; + if x == "foo" { + return; + } + x.clear(); + for x in 3..6 { + yield x + } + } + } + + let mut iter = foo(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(5)); + assert_eq!(iter.next(), None); + // `gen` blocks are fused + assert_eq!(iter.next(), None); + + let mut iter = moved(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), None); +} + +/// Ensure a generator can reborrow from a reference it captured. +/// Regression test for . +pub fn movable_gen() { + fn make_gen(r: &mut u8) -> impl Iterator { + gen move { + let a = r; + *a = 1; + yield 1; + *a = 2; + } + } + + let mut a = 1; + let mut i = make_gen(&mut a); + assert_eq!(i.next(), Some(1)); + let mut j = i; + assert_eq!(j.next(), None); +} diff --git a/tests/codegen-llvm/maybe_dangling_refs.rs b/tests/codegen-llvm/maybe_dangling_refs.rs index 07493ecac79c5..5d097151db4d7 100644 --- a/tests/codegen-llvm/maybe_dangling_refs.rs +++ b/tests/codegen-llvm/maybe_dangling_refs.rs @@ -7,7 +7,7 @@ #![crate_type = "lib"] #![feature(maybe_dangling)] -use std::mem::MaybeDangling; +use std::mem::{ManuallyDrop, MaybeDangling}; // CHECK: define {{(dso_local )?}}noundef nonnull ptr @f(ptr noundef nonnull %x) unnamed_addr #[no_mangle] @@ -15,6 +15,12 @@ pub fn f(x: MaybeDangling>) -> MaybeDangling> { x } +// CHECK: define {{(dso_local )?}}noundef nonnull ptr @f2(ptr noundef nonnull %x) unnamed_addr +#[no_mangle] +pub fn f2(x: ManuallyDrop>) -> ManuallyDrop> { + x +} + // CHECK: define {{(dso_local )?}}noundef nonnull ptr @g(ptr noundef nonnull %x) unnamed_addr #[no_mangle] pub fn g(x: MaybeDangling<&u8>) -> MaybeDangling<&u8> { From b7e5447e85cc1869c7dd26d14310cd351d3f8cf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 16:54:03 +0200 Subject: [PATCH 35/40] simplify ManuallyDrop by making it natively 'like MaybeDangling' --- compiler/rustc_middle/src/ty/sty.rs | 7 +- .../rustc_mir_build/src/builder/expr/into.rs | 4 +- library/core/src/mem/manually_drop.rs | 58 +-- src/etc/gdb_providers.py | 6 +- src/etc/natvis/libcore.natvis | 4 +- .../stacked_borrows/stack-printing.stdout | 4 +- ...move.box_new.CleanupPostBorrowck.after.mir | 2 +- ...ve.vec_macro.CleanupPostBorrowck.after.mir | 2 +- ...d_in_vec.build-{closure#0}.built.after.mir | 2 +- ....test.ElaborateDrops.after.panic-abort.mir | 2 +- ...test.ElaborateDrops.after.panic-unwind.mir | 2 +- ...loops.vec_move.runtime-optimized.after.mir | 376 +++++++++--------- .../future-sizes/async-awaiting-fut.stdout | 8 - .../async-await/future-sizes/large-arg.stdout | 6 - tests/ui/print_type_sizes/async.stdout | 4 - .../coroutine_discr_placement.stdout | 2 - 16 files changed, 208 insertions(+), 281 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 245289a0bc6cc..462f10c39866e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2189,7 +2189,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_like_maybe_dangling(self) -> bool { match self.kind() { - ty::Adt(def, _) => def.flags().contains(AdtFlags::IS_MAYBE_DANGLING), + ty::Adt(def, _) => { + // ManuallyDrop is "natively" like maybe-dangling so that we don't have + // to nest field types even deeper. + def.flags().contains(AdtFlags::IS_MAYBE_DANGLING) + || def.flags().contains(AdtFlags::IS_MANUALLY_DROP) + } ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) => true, _ => false, } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 72135df46e904..d5ce1dab1b417 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -457,9 +457,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = b.project_deeper(&[ProjectionElem::Deref], tcx); // Current type: `MaybeUninit`. Field #1 is `ManuallyDrop`. let place = place.project_to_field(FieldIdx::from_u32(1), decls, tcx); - // Current type: `ManuallyDrop`. Field #0 is `MaybeDangling`. - let place = place.project_to_field(FieldIdx::ZERO, decls, tcx); - // Current type: `MaybeDangling`. Field #0 is `T`. + // Current type: `ManuallyDrop`. Field #0 is `T`. let place = place.project_to_field(FieldIdx::ZERO, decls, tcx); // Sanity check. assert_eq!(place.ty(decls, tcx).ty, generic_args.type_at(0)); diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 6c2f77a373393..3fb844c7c2927 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,7 +1,5 @@ -use crate::cmp::Ordering; -use crate::hash::{Hash, Hasher}; -use crate::marker::{Destruct, StructuralPartialEq}; -use crate::mem::MaybeDangling; +use crate::hash::Hash; +use crate::marker::Destruct; use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; @@ -152,11 +150,11 @@ use crate::ptr; /// [`MaybeUninit`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] #[rustc_pub_transparent] pub struct ManuallyDrop { - value: MaybeDangling, + value: T, } impl ManuallyDrop { @@ -180,7 +178,7 @@ impl ManuallyDrop { #[inline(always)] #[rustc_no_writable] pub const fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value: MaybeDangling::new(value) } + ManuallyDrop { value } } /// Extracts the value from the `ManuallyDrop` container. @@ -198,9 +196,7 @@ impl ManuallyDrop { #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")] #[inline(always)] pub const fn into_inner(slot: ManuallyDrop) -> T { - // Cannot use `MaybeDangling::into_inner` as that does not yet have the desired semantics. - // SAFETY: We know this is a valid `T`. `slot` will not be dropped. - unsafe { (&raw const slot).cast::().read() } + slot.value } /// Takes the value from the `ManuallyDrop` container out. @@ -225,7 +221,7 @@ impl ManuallyDrop { pub const unsafe fn take(slot: &mut ManuallyDrop) -> T { // SAFETY: we are reading from a reference, which is guaranteed // to be valid for reads. - unsafe { ptr::read(slot.value.as_ref()) } + unsafe { ptr::read(&slot.value) } } } @@ -262,7 +258,7 @@ impl ManuallyDrop { // SAFETY: we are dropping the value pointed to by a mutable reference // which is guaranteed to be valid for writes. // It is up to the caller to make sure that `slot` isn't dropped again. - unsafe { ptr::drop_in_place(slot.value.as_mut()) } + unsafe { ptr::drop_in_place(&mut slot.value) } } } @@ -272,7 +268,7 @@ const impl Deref for ManuallyDrop { type Target = T; #[inline(always)] fn deref(&self) -> &T { - self.value.as_ref() + &self.value } } @@ -281,43 +277,9 @@ const impl Deref for ManuallyDrop { const impl DerefMut for ManuallyDrop { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - self.value.as_mut() + &mut self.value } } #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Eq for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl PartialEq for ManuallyDrop { - fn eq(&self, other: &Self) -> bool { - self.value.as_ref().eq(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl StructuralPartialEq for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Ord for ManuallyDrop { - fn cmp(&self, other: &Self) -> Ordering { - self.value.as_ref().cmp(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl PartialOrd for ManuallyDrop { - fn partial_cmp(&self, other: &Self) -> Option { - self.value.as_ref().partial_cmp(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Hash for ManuallyDrop { - fn hash(&self, state: &mut H) { - self.value.as_ref().hash(state); - } -} diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index a6ef59738c8c7..9c50d7e472000 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -330,7 +330,7 @@ def cast_to_internal(node): for i in xrange(0, length + 1): if height > 0: - child_ptr = edges[i]["value"]["value"][ZERO_FIELD] + child_ptr = edges[i]["value"]["value"] for child in children_of_node(child_ptr, height - 1): yield child if i < length: @@ -338,12 +338,12 @@ def cast_to_internal(node): key_type_size = keys.type.sizeof val_type_size = vals.type.sizeof key = ( - keys[i]["value"]["value"][ZERO_FIELD] + keys[i]["value"]["value"] if key_type_size > 0 else gdb.parse_and_eval("()") ) val = ( - vals[i]["value"]["value"][ZERO_FIELD] + vals[i]["value"]["value"] if val_type_size > 0 else gdb.parse_and_eval("()") ) diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 4e2f09743a031..20ce1cae447cf 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -35,9 +35,9 @@ - {value.__0} + {value} - value.__0 + value diff --git a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout index 296339e738455..838733078209d 100644 --- a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout +++ b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout @@ -1,6 +1,6 @@ 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] -0..1: [ SharedReadWrite Unique Unique Unique Unique Unique Unique Unique ] -0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] +0..1: [ SharedReadWrite Unique Unique Unique Unique Unique ] +0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] 0..1: [ unknown-bottom(..) ] diff --git a/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir index 0050151e89b1b..158a1ea103a63 100644 --- a/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir +++ b/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir @@ -23,7 +23,7 @@ fn box_new(_1: T) -> Box<[T; 1024]> { _4 = move _2; StorageLive(_5); _5 = copy _1; - ((((*_4).1: std::mem::ManuallyDrop<[T; 1024]>).0: std::mem::MaybeDangling<[T; 1024]>).0: [T; 1024]) = [move _5; 1024]; + (((*_4).1: std::mem::ManuallyDrop<[T; 1024]>).0: [T; 1024]) = [move _5; 1024]; StorageDead(_5); _3 = move _4; drop(_4) -> [return: bb2, unwind: bb5]; diff --git a/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir index 2410e4d31b486..d2f67cd6932c2 100644 --- a/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir +++ b/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir @@ -12,7 +12,7 @@ fn vec_macro() -> Vec { } bb1: { - ((((*_2).1: std::mem::ManuallyDrop<[i32; 8]>).0: std::mem::MaybeDangling<[i32; 8]>).0: [i32; 8]) = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32, const 6_i32, const 7_i32]; + (((*_2).1: std::mem::ManuallyDrop<[i32; 8]>).0: [i32; 8]) = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32, const 6_i32, const 7_i32]; _1 = move _2; drop(_2) -> [return: bb2, unwind: bb4]; } diff --git a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir index fc75f261ea01b..6b9927949ffe2 100644 --- a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir +++ b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir @@ -91,7 +91,7 @@ yields () bb6: { StorageDead(_19); - ((((*_5).1: std::mem::ManuallyDrop<[std::string::String; 5]>).0: std::mem::MaybeDangling<[std::string::String; 5]>).0: [std::string::String; 5]) = [move _6, move _9, move _12, move _15, move _18]; + (((*_5).1: std::mem::ManuallyDrop<[std::string::String; 5]>).0: [std::string::String; 5]) = [move _6, move _9, move _12, move _15, move _18]; drop(_18) -> [return: bb7, unwind: bb25, drop: bb15]; } diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir index afee76707e8a4..e8efb9b7c3483 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir @@ -55,7 +55,7 @@ fn test() -> Option> { _11 = copy ((_5 as Continue).0: u32); _4 = copy _11; StorageDead(_11); - ((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4]; + (((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: [u32; 1]) = [move _4]; StorageDead(_4); _2 = move _3; goto -> bb7; diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir index d44db1eb1c8c6..4da1eed4484bb 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir @@ -55,7 +55,7 @@ fn test() -> Option> { _11 = copy ((_5 as Continue).0: u32); _4 = copy _11; StorageDead(_11); - ((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4]; + (((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: [u32; 1]) = [move _4]; StorageDead(_4); _2 = move _3; goto -> bb7; diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir index a49688ae891de..cad38c437e3c3 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir @@ -3,327 +3,309 @@ fn vec_move(_1: Vec) -> () { debug v => _1; let mut _0: (); + let mut _21: std::vec::IntoIter; let mut _22: std::vec::IntoIter; - let mut _23: std::vec::IntoIter; - let mut _24: &mut std::vec::IntoIter; - let mut _25: std::option::Option; - let mut _26: isize; - let _28: (); + let mut _23: &mut std::vec::IntoIter; + let mut _24: std::option::Option; + let mut _25: isize; + let _27: (); scope 1 { - debug iter => _23; - let _27: impl Sized; + debug iter => _22; + let _26: impl Sized; scope 2 { - debug x => _27; + debug x => _26; } } scope 3 (inlined as IntoIterator>::into_iter) { debug self => _1; - let _3: std::mem::ManuallyDrop>; - let mut _4: *const std::alloc::Global; - let mut _8: usize; - let mut _10: *mut impl Sized; - let mut _11: *const impl Sized; - let mut _12: usize; - let _29: &std::vec::Vec; - let mut _30: &std::mem::ManuallyDrop>; - let mut _31: &alloc::raw_vec::RawVec; - let mut _32: &std::mem::ManuallyDrop>; - let _33: &std::vec::Vec; - let mut _34: &std::mem::ManuallyDrop>; - let _35: &std::vec::Vec; - let mut _36: &std::mem::ManuallyDrop>; - let mut _37: &alloc::raw_vec::RawVec; - let mut _38: &std::mem::ManuallyDrop>; + let _2: std::mem::ManuallyDrop>; + let mut _3: *const std::alloc::Global; + let mut _7: usize; + let mut _9: *mut impl Sized; + let mut _10: *const impl Sized; + let mut _11: usize; + let _28: &std::vec::Vec; + let mut _29: &std::mem::ManuallyDrop>; + let mut _30: &alloc::raw_vec::RawVec; + let mut _31: &std::mem::ManuallyDrop>; + let _32: &std::vec::Vec; + let mut _33: &std::mem::ManuallyDrop>; + let _34: &std::vec::Vec; + let mut _35: &std::mem::ManuallyDrop>; + let mut _36: &alloc::raw_vec::RawVec; + let mut _37: &std::mem::ManuallyDrop>; scope 4 { - debug me => _3; + debug me => _2; scope 5 { - debug alloc => const ManuallyDrop:: {{ value: MaybeDangling::(std::alloc::Global) }}; - let _6: std::ptr::NonNull; + debug alloc => const ManuallyDrop:: {{ value: std::alloc::Global }}; + let _5: std::ptr::NonNull; scope 6 { - debug buf => _6; - let _7: *mut impl Sized; + debug buf => _5; + let _6: *mut impl Sized; scope 7 { - debug begin => _7; + debug begin => _6; scope 8 { - debug end => _11; - let _20: usize; + debug end => _10; + let _19: usize; scope 9 { - debug cap => _20; + debug cap => _19; } - scope 45 (inlined > as Deref>::deref) { - debug self => _38; - scope 46 (inlined MaybeDangling::>::as_ref) { - } - } - scope 47 (inlined alloc::raw_vec::RawVec::::capacity) { + scope 39 (inlined > as Deref>::deref) { debug self => _37; - let mut _39: &alloc::raw_vec::RawVecInner; - scope 48 (inlined std::mem::size_of::) { + } + scope 40 (inlined alloc::raw_vec::RawVec::::capacity) { + debug self => _36; + let mut _38: &alloc::raw_vec::RawVecInner; + scope 41 (inlined std::mem::size_of::) { } - scope 49 (inlined alloc::raw_vec::RawVecInner::capacity) { - debug self => _39; + scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) { + debug self => _38; debug elem_size => const ::SIZE; - let mut _21: core::num::niche_types::UsizeNoHighBit; - scope 50 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { - debug self => _21; + let mut _20: core::num::niche_types::UsizeNoHighBit; + scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { + debug self => _20; } } } } - scope 29 (inlined > as Deref>::deref) { - debug self => _34; - scope 30 (inlined MaybeDangling::>::as_ref) { - } - } - scope 31 (inlined Vec::::len) { + scope 25 (inlined > as Deref>::deref) { debug self => _33; - let mut _13: bool; - scope 32 { + } + scope 26 (inlined Vec::::len) { + debug self => _32; + let mut _12: bool; + scope 27 { } } - scope 33 (inlined std::ptr::mut_ptr::::wrapping_byte_add) { - debug self => _7; - debug count => _12; - let mut _14: *mut u8; - let mut _18: *mut u8; - let mut _19: *const impl Sized; - scope 34 (inlined std::ptr::mut_ptr::::cast::) { - debug self => _7; + scope 28 (inlined std::ptr::mut_ptr::::wrapping_byte_add) { + debug self => _6; + debug count => _11; + let mut _13: *mut u8; + let mut _17: *mut u8; + let mut _18: *const impl Sized; + scope 29 (inlined std::ptr::mut_ptr::::cast::) { + debug self => _6; } - scope 35 (inlined std::ptr::mut_ptr::::wrapping_add) { - debug self => _14; - debug count => _12; - let mut _15: isize; - scope 36 (inlined std::ptr::mut_ptr::::wrapping_offset) { - debug self => _14; - debug count => _15; + scope 30 (inlined std::ptr::mut_ptr::::wrapping_add) { + debug self => _13; + debug count => _11; + let mut _14: isize; + scope 31 (inlined std::ptr::mut_ptr::::wrapping_offset) { + debug self => _13; + debug count => _14; + let mut _15: *const u8; let mut _16: *const u8; - let mut _17: *const u8; } } - scope 37 (inlined std::ptr::mut_ptr::::with_metadata_of::) { - debug self => _18; - debug meta => _19; - scope 38 (inlined std::ptr::metadata::) { - debug ptr => _19; + scope 32 (inlined std::ptr::mut_ptr::::with_metadata_of::) { + debug self => _17; + debug meta => _18; + scope 33 (inlined std::ptr::metadata::) { + debug ptr => _18; } - scope 39 (inlined std::ptr::from_raw_parts_mut::) { + scope 34 (inlined std::ptr::from_raw_parts_mut::) { } } } - scope 40 (inlined > as Deref>::deref) { - debug self => _36; - scope 41 (inlined MaybeDangling::>::as_ref) { - } - } - scope 42 (inlined Vec::::len) { + scope 35 (inlined > as Deref>::deref) { debug self => _35; - let mut _9: bool; - scope 43 { + } + scope 36 (inlined Vec::::len) { + debug self => _34; + let mut _8: bool; + scope 37 { } } - scope 44 (inlined #[track_caller] std::ptr::mut_ptr::::add) { - debug self => _7; - debug count => _8; + scope 38 (inlined #[track_caller] std::ptr::mut_ptr::::add) { + debug self => _6; + debug count => _7; } } - scope 28 (inlined NonNull::::as_ptr) { - debug self => _6; - } - } - scope 20 (inlined > as Deref>::deref) { - debug self => _32; - scope 21 (inlined MaybeDangling::>::as_ref) { + scope 24 (inlined NonNull::::as_ptr) { + debug self => _5; } } - scope 22 (inlined alloc::raw_vec::RawVec::::non_null) { + scope 17 (inlined > as Deref>::deref) { debug self => _31; - scope 23 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _5: std::ptr::NonNull; - scope 24 (inlined std::ptr::Unique::::cast::) { - scope 25 (inlined NonNull::::cast::) { - scope 26 (inlined NonNull::::as_ptr) { + } + scope 18 (inlined alloc::raw_vec::RawVec::::non_null) { + debug self => _30; + scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _4: std::ptr::NonNull; + scope 20 (inlined std::ptr::Unique::::cast::) { + scope 21 (inlined NonNull::::cast::) { + scope 22 (inlined NonNull::::as_ptr) { } } } - scope 27 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { } } } } - scope 12 (inlined > as Deref>::deref) { - debug self => _30; - scope 13 (inlined MaybeDangling::>::as_ref) { - } - } - scope 14 (inlined Vec::::allocator) { + scope 11 (inlined > as Deref>::deref) { debug self => _29; - scope 15 (inlined alloc::raw_vec::RawVec::::allocator) { - scope 16 (inlined alloc::raw_vec::RawVecInner::allocator) { + } + scope 12 (inlined Vec::::allocator) { + debug self => _28; + scope 13 (inlined alloc::raw_vec::RawVec::::allocator) { + scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) { } } } - scope 17 (inlined #[track_caller] std::ptr::read::) { - debug src => _4; + scope 15 (inlined #[track_caller] std::ptr::read::) { + debug src => _3; } - scope 18 (inlined ManuallyDrop::::new) { + scope 16 (inlined ManuallyDrop::::new) { debug value => const std::alloc::Global; - scope 19 (inlined MaybeDangling::::new) { - } } } scope 10 (inlined ManuallyDrop::>::new) { debug value => _1; - let mut _2: std::mem::MaybeDangling>; - scope 11 (inlined MaybeDangling::>::new) { - } } } bb0: { - StorageLive(_22); - StorageLive(_11); - StorageLive(_20); - StorageLive(_5); - StorageLive(_17); - StorageLive(_3); - StorageLive(_2); - _2 = MaybeDangling::>(copy _1); - _3 = ManuallyDrop::> { value: move _2 }; - StorageDead(_2); + StorageLive(_21); + StorageLive(_10); + StorageLive(_19); StorageLive(_4); - // DBG: _30 = &_3; - // DBG: _29 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _4 = &raw const (((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); - StorageDead(_4); + StorageLive(_16); + StorageLive(_2); + _2 = ManuallyDrop::> { value: copy _1 }; + StorageLive(_3); + // DBG: _29 = &_2; + // DBG: _28 = &(_2.0: std::vec::Vec); + _3 = &raw const ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); + StorageDead(_3); + StorageLive(_5); + // DBG: _31 = &_2; + // DBG: _30 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + _4 = copy (((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _5 = copy _4 as std::ptr::NonNull (Transmute); StorageLive(_6); - // DBG: _32 = &_3; - // DBG: _31 = &(((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec); - _5 = copy ((((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _6 = copy _5 as std::ptr::NonNull (Transmute); - StorageLive(_7); - _7 = copy _5 as *mut impl Sized (Transmute); + _6 = copy _4 as *mut impl Sized (Transmute); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_8); - // DBG: _36 = &_3; - // DBG: _35 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _8 = copy (((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).1: usize); StorageLive(_9); - _9 = Le(copy _8, const ::MAX_SLICE_LEN); - assume(move _9); - StorageDead(_9); - _10 = Offset(copy _7, copy _8); - _11 = copy _10 as *const impl Sized (PtrToPtr); + StorageLive(_7); + // DBG: _35 = &_2; + // DBG: _34 = &(_2.0: std::vec::Vec); + _7 = copy ((_2.0: std::vec::Vec).1: usize); + StorageLive(_8); + _8 = Le(copy _7, const ::MAX_SLICE_LEN); + assume(move _8); StorageDead(_8); - StorageDead(_10); + _9 = Offset(copy _6, copy _7); + _10 = copy _9 as *const impl Sized (PtrToPtr); + StorageDead(_7); + StorageDead(_9); goto -> bb4; } bb2: { + StorageLive(_11); + // DBG: _33 = &_2; + // DBG: _32 = &(_2.0: std::vec::Vec); + _11 = copy ((_2.0: std::vec::Vec).1: usize); StorageLive(_12); - // DBG: _34 = &_3; - // DBG: _33 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _12 = copy (((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).1: usize); + _12 = Le(copy _11, const ::MAX_SLICE_LEN); + assume(move _12); + StorageDead(_12); + StorageLive(_17); StorageLive(_13); - _13 = Le(copy _12, const ::MAX_SLICE_LEN); - assume(move _13); - StorageDead(_13); - StorageLive(_18); + _13 = copy _4 as *mut u8 (Transmute); StorageLive(_14); - _14 = copy _5 as *mut u8 (Transmute); + _14 = copy _11 as isize (IntToInt); StorageLive(_15); - _15 = copy _12 as isize (IntToInt); - StorageLive(_16); - _16 = copy _5 as *const u8 (Transmute); - _17 = arith_offset::(move _16, move _15) -> [return: bb3, unwind unreachable]; + _15 = copy _4 as *const u8 (Transmute); + _16 = arith_offset::(move _15, move _14) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_16); - _18 = copy _17 as *mut u8 (PtrToPtr); StorageDead(_15); + _17 = copy _16 as *mut u8 (PtrToPtr); StorageDead(_14); - StorageLive(_19); - _19 = copy _5 as *const impl Sized (Transmute); - StorageDead(_19); + StorageDead(_13); + StorageLive(_18); + _18 = copy _4 as *const impl Sized (Transmute); StorageDead(_18); - StorageDead(_12); - _11 = copy _17 as *const impl Sized (PtrToPtr); + StorageDead(_17); + StorageDead(_11); + _10 = copy _16 as *const impl Sized (PtrToPtr); goto -> bb4; } bb4: { - // DBG: _38 = &_3; - // DBG: _37 = &(((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec); - // DBG: _39 = &((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + // DBG: _37 = &_2; + // DBG: _36 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + // DBG: _38 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); switchInt(const ::SIZE) -> [0: bb5, otherwise: bb6]; } bb5: { - _20 = const usize::MAX; + _19 = const usize::MAX; goto -> bb7; } bb6: { - StorageLive(_21); - _21 = copy (((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit); - _20 = copy _21 as usize (Transmute); - StorageDead(_21); + StorageLive(_20); + _20 = copy ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit); + _19 = copy _20 as usize (Transmute); + StorageDead(_20); goto -> bb7; } bb7: { - _22 = std::vec::IntoIter:: { buf: copy _6, phantom: const ZeroSized: PhantomData, cap: move _20, alloc: const ManuallyDrop:: {{ value: MaybeDangling::(std::alloc::Global) }}, ptr: copy _6, end: copy _11 }; - StorageDead(_7); + _21 = std::vec::IntoIter:: { buf: copy _5, phantom: const ZeroSized: PhantomData, cap: move _19, alloc: const ManuallyDrop:: {{ value: std::alloc::Global }}, ptr: copy _5, end: copy _10 }; StorageDead(_6); - StorageDead(_3); - StorageDead(_17); StorageDead(_5); - StorageDead(_20); - StorageDead(_11); - StorageLive(_23); - _23 = move _22; + StorageDead(_2); + StorageDead(_16); + StorageDead(_4); + StorageDead(_19); + StorageDead(_10); + StorageLive(_22); + _22 = move _21; goto -> bb8; } bb8: { - StorageLive(_25); StorageLive(_24); - _24 = &mut _23; - _25 = as Iterator>::next(move _24) -> [return: bb9, unwind: bb15]; + StorageLive(_23); + _23 = &mut _22; + _24 = as Iterator>::next(move _23) -> [return: bb9, unwind: bb15]; } bb9: { - _26 = discriminant(_25); - switchInt(move _26) -> [0: bb10, 1: bb12, otherwise: bb14]; + _25 = discriminant(_24); + switchInt(move _25) -> [0: bb10, 1: bb12, otherwise: bb14]; } bb10: { + StorageDead(_23); StorageDead(_24); - StorageDead(_25); - drop(_23) -> [return: bb11, unwind continue]; + drop(_22) -> [return: bb11, unwind continue]; } bb11: { - StorageDead(_23); StorageDead(_22); + StorageDead(_21); return; } bb12: { - StorageLive(_27); - _27 = move ((_25 as Some).0: impl Sized); - _28 = opaque::(move _27) -> [return: bb13, unwind: bb15]; + StorageLive(_26); + _26 = move ((_24 as Some).0: impl Sized); + _27 = opaque::(move _26) -> [return: bb13, unwind: bb15]; } bb13: { - StorageDead(_27); + StorageDead(_26); + StorageDead(_23); StorageDead(_24); - StorageDead(_25); goto -> bb8; } @@ -332,7 +314,7 @@ fn vec_move(_1: Vec) -> () { } bb15 (cleanup): { - drop(_23) -> [return: bb16, unwind terminate(cleanup)]; + drop(_22) -> [return: bb16, unwind terminate(cleanup)]; } bb16 (cleanup): { diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index 90381a12bbd4b..775f683a8f926 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -7,8 +7,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes -print-type-size field `.0`: 3077 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3077 bytes print-type-size field `.uninit`: 0 bytes @@ -38,8 +36,6 @@ print-type-size variant `Panicked`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes -print-type-size field `.0`: 1025 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes @@ -93,10 +89,6 @@ print-type-size type: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 byte print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeDangling`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index f65c5c1a7cb78..b6051da95ca42 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -7,8 +7,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes -print-type-size field `.0`: 3075 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3075 bytes print-type-size field `.uninit`: 0 bytes @@ -26,8 +24,6 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes -print-type-size field `.0`: 2050 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 2050 bytes print-type-size field `.uninit`: 0 bytes @@ -45,8 +41,6 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes -print-type-size field `.0`: 1025 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index c068818fdc9a5..0499531158844 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -12,8 +12,6 @@ print-type-size variant `Panicked`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `std::mem::MaybeDangling<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes -print-type-size field `.0`: 8192 bytes print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes @@ -53,8 +51,6 @@ print-type-size type: `std::ptr::NonNull>`: 8 bytes, alig print-type-size field `.pointer`: 8 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout index b51beb514ba80..4ce1ce46f6e82 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout @@ -11,8 +11,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop`: 4 bytes, alignment: 4 bytes print-type-size field `.value`: 4 bytes -print-type-size type: `std::mem::MaybeDangling`: 4 bytes, alignment: 4 bytes -print-type-size field `.0`: 4 bytes print-type-size type: `std::mem::MaybeUninit`: 4 bytes, alignment: 4 bytes print-type-size variant `MaybeUninit`: 4 bytes print-type-size field `.uninit`: 0 bytes From 95d43bf5355ae272eb6b9b33202a3a8cae4fca4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 12:47:05 +0200 Subject: [PATCH 36/40] remove no-longer-needed MaybeDangling from thread spawning --- library/std/src/thread/lifecycle.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/std/src/thread/lifecycle.rs b/library/std/src/thread/lifecycle.rs index d3a97bbf08fa2..11ab2190c5444 100644 --- a/library/std/src/thread/lifecycle.rs +++ b/library/std/src/thread/lifecycle.rs @@ -7,7 +7,6 @@ use super::thread::Thread; use super::{Result, spawnhook}; use crate::cell::UnsafeCell; use crate::marker::PhantomData; -use crate::mem::MaybeDangling; use crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::{AsInner, IntoInner, thread as imp}; @@ -57,14 +56,9 @@ where Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None), _marker: PhantomData }); let their_packet = my_packet.clone(); - // Pass `f` in `MaybeDangling` because actually that closure might *run longer than the lifetime of `F`*. - // See for more details. - let f = MaybeDangling::new(f); - // The entrypoint of the Rust thread, after platform-specific thread // initialization is done. let rust_start = move || { - let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.inherit_and_run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) From 60b5f88cce0137355b4dba9deec2c82024239090 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2026 10:59:10 +0200 Subject: [PATCH 37/40] add another movable-generator regression test --- src/tools/miri/tests/pass/generators.rs | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tools/miri/tests/pass/generators.rs b/src/tools/miri/tests/pass/generators.rs index 67a169bcfe821..c5ab3fcb8e28f 100644 --- a/src/tools/miri/tests/pass/generators.rs +++ b/src/tools/miri/tests/pass/generators.rs @@ -1,10 +1,15 @@ //@edition: 2024 +//@revisions: stack tree tree_implicit_writes +//@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes +//@[tree]compile-flags: -Zmiri-tree-borrows + #![feature(gen_blocks)] fn main() { basic(); iterate(); movable_gen(); + movable_gen2(); } fn basic() { @@ -78,3 +83,33 @@ pub fn movable_gen() { let mut j = i; assert_eq!(j.next(), None); } + +/// Regression test for . +fn movable_gen2() { + // a struct that has a drop flag and contains a reference + struct DropMut(&'static mut T); + impl Drop for DropMut { + fn drop(&mut self) { + drop(unsafe { Box::from_raw(self.0) }); + } + } + + let mut a = gen { + let b = DropMut(Box::leak(Box::new(1))); + + // create a drop flag on `b` + let c; + if true { + c = b; // and ensure it's set to false + } else { + c = DropMut(Box::leak(Box::new(2))); + } + + *c.0 = 3; + 4.yield; + *c.0 = 5; + }; + let _ = a.next(); + let mut d = a; + let _ = d.next(); +} From 14ac84f8f3fba0e56d4b5b7b2856abfd1247c941 Mon Sep 17 00:00:00 2001 From: Philip Kannegaard Hayes Date: Thu, 27 Aug 2026 14:38:31 -0700 Subject: [PATCH 38/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..5a91305c5b9f0 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_mut() // 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 297c72a614ad5f9ed8f82a04a0a8bb49a06d893b Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 18 Aug 2026 00:26:37 +0200 Subject: [PATCH 39/40] break rustc_expand-rustc_middle dependency --- Cargo.lock | 15 +++- compiler/rustc_expand/Cargo.toml | 2 - compiler/rustc_expand/src/lib.rs | 4 - compiler/rustc_expand/src/mbe/diagnostics.rs | 11 ++- compiler/rustc_expand/src/mbe/macro_parser.rs | 8 +- compiler/rustc_expand/src/proc_macro.rs | 81 +++--------------- compiler/rustc_expand_queries/Cargo.toml | 20 +++++ compiler/rustc_expand_queries/src/derive.rs | 82 +++++++++++++++++++ compiler/rustc_expand_queries/src/lib.rs | 13 +++ compiler/rustc_interface/Cargo.toml | 1 + compiler/rustc_interface/src/callbacks.rs | 1 + compiler/rustc_interface/src/passes.rs | 2 +- 12 files changed, 150 insertions(+), 90 deletions(-) create mode 100644 compiler/rustc_expand_queries/Cargo.toml create mode 100644 compiler/rustc_expand_queries/src/derive.rs create mode 100644 compiler/rustc_expand_queries/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b398d06c347df..d61f745e0bc3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4055,19 +4055,29 @@ dependencies = [ "rustc_lexer", "rustc_lint_defs", "rustc_macros", - "rustc_middle", "rustc_parse", "rustc_proc_macro", "rustc_serialize", "rustc_session", "rustc_span", "rustc_structures", - "scoped-tls", "smallvec", "thin-vec", "tracing", ] +[[package]] +name = "rustc_expand_queries" +version = "0.0.0" +dependencies = [ + "rustc_ast", + "rustc_expand", + "rustc_middle", + "rustc_proc_macro", + "rustc_span", + "scoped-tls", +] + [[package]] name = "rustc_feature" version = "0.0.0" @@ -4271,6 +4281,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_expand_queries", "rustc_feature", "rustc_fs_util", "rustc_hir", diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 0f216aa9f68df..1d0864ff7b201 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -20,7 +20,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } -rustc_middle = { path = "../rustc_middle" } rustc_parse = { path = "../rustc_parse" } # We must use the proc_macro version that we will compile proc-macros against, # not the one from our own sysroot. @@ -29,7 +28,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_structures = { path = "../rustc_structures" } -scoped-tls = "1.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.19" tracing = "0.1" diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 8bbca0ddf0f90..c81d9eb12aa48 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -23,7 +23,3 @@ pub mod config; pub mod expand; pub mod module; pub mod proc_macro; - -pub fn provide(providers: &mut rustc_middle::query::Providers) { - providers.derive_macro_expansion = proc_macro::provide_derive_macro_expansion; -} diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 89b4aac3299fc..024a0542a5f64 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -6,7 +6,6 @@ use rustc_attr_ir::diagnostic::{CustomDiagnostic, Directive, FormatArgs}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, pluralize}; use rustc_macros::Subdiagnostic; -use rustc_middle::bug; use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; @@ -203,7 +202,7 @@ impl BestFailure { impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'matcher> { fn prepare(&mut self, which_matcher: WhichMatcher, matcher: &'matcher [MatcherLoc]) { if self.current.is_some() { - bug!("`Self::after_arm()` was not called to clean up context"); + panic!("`Self::after_arm()` was not called to clean up context"); } self.current = Some((which_matcher, matcher)); @@ -236,12 +235,12 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match } Failure => { if self.best_failure.is_none() { - bug!("A matching failure occurred but `Self::failure()` was not called"); + panic!("A matching failure occurred but `Self::failure()` was not called"); } } Ambiguity => { if self.result.is_none() { - bug!("An ambiguity error occurred but `Self::ambiguity()` was not called"); + panic!("An ambiguity error occurred but `Self::ambiguity()` was not called"); } } ErrorReported(guar) => self.result = Some((self.root_span, guar)), @@ -253,7 +252,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match fn failure(&mut self, parser: &Parser<'_>) { let Some((which_matcher, _)) = self.current else { - bug!("`Self::prepare()` was not called to initialize context"); + panic!("`Self::prepare()` was not called to initialize context"); }; let mut token = parser.token; @@ -290,7 +289,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match fn ambiguity(&mut self, parser: &Parser<'_>) { let Some((_, matcher)) = self.current else { - bug!("`Self::prepare()` was not called to initialize context"); + panic!("`Self::prepare()` was not called to initialize context"); }; #[expect( diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 95a4ebc63d38b..3e94e0ca34773 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -80,7 +80,6 @@ pub(crate) use ParseResult::*; use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_middle::span_bug; use rustc_parse::parser::{ParseNtResult, Parser, token_descr}; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span}; @@ -732,17 +731,14 @@ impl TtParser { // `NamedParseResult`. Otherwise, it's an error. let mut ret_val = FxHashMap::default(); for loc in matcher { - if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc + if let &MatcherLoc::MetaVarDecl { bind, .. } = loc && ret_val .insert(MacroRulesNormalizedIdent::new(bind), res.next().unwrap()) .is_some() { // Duplicate binds are checked for when the macro definition is processed, // and should have prevented the definition from ever being used. - span_bug!( - span, - "duplicate meta-variable binding went undetected at macro definition" - ) + panic!("duplicate meta-variable binding went undetected at macro definition") } } ret_val diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 105d2d796aa80..5e01b851b75c7 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -1,8 +1,8 @@ use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; +use rustc_data_structures::AtomicRef; use rustc_data_structures::profiling::TimingGuard; use rustc_errors::ErrorGuaranteed; -use rustc_middle::ty::{self, TyCtxt}; use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser}; use rustc_proc_macro as pm; use rustc_session::Session; @@ -113,14 +113,7 @@ impl MultiItemModifier for DeriveProcMacro { let res = if ecx.sess.opts.incremental.is_some() && ecx.sess.opts.unstable_opts.cache_proc_macros { - ty::tls::with(|tcx| { - let input = &*tcx.arena.alloc(input); - let key: (LocalExpnId, &TokenStream) = (invoc_id, input); - - QueryDeriveExpandCtx::enter(ecx, self.client, move || { - tcx.derive_macro_expansion(key).cloned() - }) - }) + (*EXPAND_DERIVE_MACRO_CACHED)(invoc_id, input, ecx, self.client) } else { expand_derive_macro(invoc_id, input, ecx, self.client) }; @@ -163,24 +156,9 @@ impl MultiItemModifier for DeriveProcMacro { } } -/// Provide a query for computing the output of a derive macro. -pub(super) fn provide_derive_macro_expansion<'tcx>( - tcx: TyCtxt<'tcx>, - key: (LocalExpnId, &'tcx TokenStream), -) -> Result<&'tcx TokenStream, ()> { - let (invoc_id, input) = key; - - // Make sure that we invalidate the query when the crate defining the proc macro changes - let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate); - - QueryDeriveExpandCtx::with(|ecx, client| { - expand_derive_macro(invoc_id, input.clone(), ecx, client).map(|ts| &*tcx.arena.alloc(ts)) - }) -} - type DeriveClient = pm::bridge::client::Client; -fn expand_derive_macro( +pub fn expand_derive_macro( invoc_id: LocalExpnId, input: TokenStream, ecx: &mut ExtCtxt<'_>, @@ -216,47 +194,12 @@ fn expand_derive_macro( } } -/// Stores the context necessary to expand a derive proc macro via a query. -struct QueryDeriveExpandCtx { - /// Type-erased version of `&mut ExtCtxt` - expansion_ctx: *mut (), - client: DeriveClient, -} - -impl QueryDeriveExpandCtx { - /// Store the extension context and the client into the thread local value. - /// It will be accessible via the `with` method while `f` is active. - fn enter(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R - where - F: FnOnce() -> R, - { - // We need erasure to get rid of the lifetime - let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client }; - DERIVE_EXPAND_CTX.set(&ctx, f) - } - - /// Accesses the thread local value of the derive expansion context. - /// Must be called while the `enter` function is active. - fn with(f: F) -> R - where - F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R, - { - DERIVE_EXPAND_CTX.with(|ctx| { - let ectx = { - let casted = ctx.expansion_ctx.cast::>(); - // SAFETY: We can only get the value from `with` while the `enter` function - // is active (on the callstack), and that function's signature ensures that the - // lifetime is valid. - // If `with` is called at some other time, it will panic due to usage of - // `scoped_tls::with`. - unsafe { casted.as_mut().unwrap() } - }; - - f(ectx, ctx.client) - }) - } -} - -// When we invoke a query to expand a derive proc macro, we need to provide it with the expansion -// context and derive Client. We do that using a thread-local. -scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx); +pub static EXPAND_DERIVE_MACRO_CACHED: AtomicRef< + fn(LocalExpnId, TokenStream, &mut ExtCtxt<'_>, DeriveClient) -> Result, +> = AtomicRef::new( + &(|_, _, _: &mut ExtCtxt<'_>, _| -> Result<_, _> { + panic!( + "`EXPAND_DERIVE_MACRO_CACHED` callback was not setup; it must be set in `rustc_interface::callbacks`" + ) + } as _), +); diff --git a/compiler/rustc_expand_queries/Cargo.toml b/compiler/rustc_expand_queries/Cargo.toml new file mode 100644 index 0000000000000..abf932e24716d --- /dev/null +++ b/compiler/rustc_expand_queries/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "rustc_expand_queries" +version = "0.0.0" +edition = "2024" +build = false + +[lib] +doctest = false + +[dependencies] +# tidy-alphabetical-start +rustc_ast = { path = "../rustc_ast" } +rustc_expand = { path = "../rustc_expand" } +rustc_middle = { path = "../rustc_middle" } +# We must use the proc_macro version that we will compile proc-macros against, +# not the one from our own sysroot. +rustc_proc_macro = { path = "../rustc_proc_macro" } +rustc_span = { path = "../rustc_span" } +scoped-tls = "1.0" +# tidy-alphabetical-end diff --git a/compiler/rustc_expand_queries/src/derive.rs b/compiler/rustc_expand_queries/src/derive.rs new file mode 100644 index 0000000000000..1254013ad89bb --- /dev/null +++ b/compiler/rustc_expand_queries/src/derive.rs @@ -0,0 +1,82 @@ +use rustc_ast::tokenstream::TokenStream; +use rustc_expand::base::ExtCtxt; +use rustc_middle::ty::{TyCtxt, tls}; +use rustc_proc_macro as pm; +use rustc_span::LocalExpnId; + +type DeriveClient = pm::bridge::client::Client; + +/// Stores the context necessary to expand a derive proc macro via a query. +struct QueryDeriveExpandCtx { + /// Type-erased version of `&mut ExtCtxt` + expansion_ctx: *mut (), + client: DeriveClient, +} + +impl QueryDeriveExpandCtx { + /// Store the extension context and the client into the thread local value. + /// It will be accessible via the `with` method while `f` is active. + fn enter(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R + where + F: FnOnce() -> R, + { + // We need erasure to get rid of the lifetime + let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client }; + DERIVE_EXPAND_CTX.set(&ctx, f) + } + + /// Accesses the thread local value of the derive expansion context. + /// Must be called while the `enter` function is active. + fn with(f: F) -> R + where + F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R, + { + DERIVE_EXPAND_CTX.with(|ctx| { + let ectx = { + let casted = ctx.expansion_ctx.cast::>(); + // SAFETY: We can only get the value from `with` while the `enter` function + // is active (on the callstack), and that function's signature ensures that the + // lifetime is valid. + // If `with` is called at some other time, it will panic due to usage of + // `scoped_tls::with`. + unsafe { casted.as_mut().unwrap() } + }; + + f(ectx, ctx.client) + }) + } +} + +// When we invoke a query to expand a derive proc macro, we need to provide it with the expansion +// context and derive Client. We do that using a thread-local. +scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx); + +pub(crate) fn expand_derive_macro_cached( + invoc_id: LocalExpnId, + input: TokenStream, + ecx: &mut ExtCtxt<'_>, + client: DeriveClient, +) -> Result { + tls::with(|tcx| { + let input = &*tcx.arena.alloc(input); + let key: (LocalExpnId, &TokenStream) = (invoc_id, input); + + QueryDeriveExpandCtx::enter(ecx, client, move || tcx.derive_macro_expansion(key).cloned()) + }) +} + +/// Provide a query for computing the output of a derive macro. +pub(crate) fn derive_macro_expansion<'tcx>( + tcx: TyCtxt<'tcx>, + key: (LocalExpnId, &'tcx TokenStream), +) -> Result<&'tcx TokenStream, ()> { + let (invoc_id, input) = key; + + // Make sure that we invalidate the query when the crate defining the proc macro changes + let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate); + + QueryDeriveExpandCtx::with(|ecx, client| { + rustc_expand::proc_macro::expand_derive_macro(invoc_id, input.clone(), ecx, client) + .map(|ts| &*tcx.arena.alloc(ts)) + }) +} diff --git a/compiler/rustc_expand_queries/src/lib.rs b/compiler/rustc_expand_queries/src/lib.rs new file mode 100644 index 0000000000000..ef669460aeec2 --- /dev/null +++ b/compiler/rustc_expand_queries/src/lib.rs @@ -0,0 +1,13 @@ +#![allow(internal_features, reason = "proc macro internals")] +#![feature(proc_macro_internals)] + +mod derive; + +pub fn setup_callbacks() { + rustc_expand::proc_macro::EXPAND_DERIVE_MACRO_CACHED + .swap(&(derive::expand_derive_macro_cached as _)); +} + +pub fn provide(providers: &mut rustc_middle::query::Providers) { + providers.derive_macro_expansion = derive::derive_macro_expansion; +} diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 4e99ba176d57b..cbf961f4cc58b 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -20,6 +20,7 @@ rustc_crate_store = { path = "../rustc_crate_store" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } +rustc_expand_queries = { path = "../rustc_expand_queries" } rustc_feature = { path = "../rustc_feature" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 2fad0297e31e0..a0a2317dc7532 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -91,4 +91,5 @@ pub fn setup_callbacks() { rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); rustc_feature::TRACK_FEATURE.swap(&(track_feature as _)); + rustc_expand_queries::setup_callbacks(); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c829864b02288..3a8a4224ffa95 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -907,7 +907,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { providers.queries.proc_macro_decls_static = |tcx, _| tcx.hir_crate_items(()).proc_macro_decls(); rustc_ast_lowering::provide(&mut providers.queries); limits::provide(&mut providers.queries); - rustc_expand::provide(&mut providers.queries); + rustc_expand_queries::provide(&mut providers.queries); rustc_const_eval::provide(providers); rustc_middle::hir::provide(&mut providers.queries); rustc_borrowck::provide(&mut providers.queries); From de40569de1c3e95afde2b1e60206599d3e113645 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:28:41 +0200 Subject: [PATCH 40/40] bless bootstrap --- .../core/builder/cli_paths/snapshots/x_bench.snap | 1 + .../cli_paths/snapshots/x_build_compiler.snap | 1 + .../core/builder/cli_paths/snapshots/x_check.snap | 1 + .../cli_paths/snapshots/x_check_compiler.snap | 1 + .../x_check_compiletest_include_default_paths.snap | 1 + .../core/builder/cli_paths/snapshots/x_clippy.snap | 1 + .../src/core/builder/cli_paths/snapshots/x_fix.snap | 1 + .../src/core/builder/cli_paths/snapshots/x_test.snap | 1 + .../cli_paths/snapshots/x_test_skip_coverage.snap | 1 + .../snapshots/x_test_skip_coverage_map.snap | 1 + .../snapshots/x_test_skip_coverage_run.snap | 1 + .../cli_paths/snapshots/x_test_skip_tests.snap | 1 + .../snapshots/x_test_skip_tests_coverage.snap | 1 + .../cli_paths/snapshots/x_test_skip_tests_etc.snap | 1 + src/bootstrap/src/core/builder/tests.rs | 12 ++++++------ 15 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap index bb55f31c405d6..c609f5ffd51fa 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap @@ -45,6 +45,7 @@ expression: bench - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build_compiler.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build_compiler.snap index 9d3ff75cc1cce..41529a664a189 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build_compiler.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build_compiler.snap @@ -27,6 +27,7 @@ expression: build compiler - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap index 812bc18078999..d5754846441a2 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap @@ -29,6 +29,7 @@ expression: check - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiler.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiler.snap index dc069febfcebe..efedf514001c2 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiler.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiler.snap @@ -29,6 +29,7 @@ expression: check compiler - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap index 921060318f5e5..cb48844356717 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap @@ -29,6 +29,7 @@ expression: check compiletest --include-default-paths - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_clippy.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_clippy.snap index dfb838638bf68..17b69d85ff821 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_clippy.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_clippy.snap @@ -44,6 +44,7 @@ expression: clippy - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap index 356be4863d1a6..8ed386a4f219a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap @@ -29,6 +29,7 @@ expression: fix - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index 49a1c04c6af63..32ed54050dc3d 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -93,6 +93,7 @@ expression: test - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index 397f8dbd794a3..d1cdf81a14e08 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -90,6 +90,7 @@ expression: test --skip=coverage - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap index d4723f9070859..df4b8a2ce1299 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap @@ -93,6 +93,7 @@ expression: test --skip=coverage-map - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap index 40d211627d7e0..75992df8aa616 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap @@ -93,6 +93,7 @@ expression: test --skip=coverage-run - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap index bdd627ae37cc3..72839a9dddb10 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap @@ -54,6 +54,7 @@ expression: test --skip=tests - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap index 7551afd31a79c..a44052fac41f9 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap @@ -90,6 +90,7 @@ expression: test --skip=tests/coverage - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap index 4457208ab56b9..ee846481847cd 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap @@ -38,6 +38,7 @@ expression: test --skip=tests --skip=library --skip=tidyselftest - Set({compiler/rustc_error_messages}) - Set({compiler/rustc_errors}) - Set({compiler/rustc_expand}) + - Set({compiler/rustc_expand_queries}) - Set({compiler/rustc_feature}) - Set({compiler/rustc_fs_util}) - Set({compiler/rustc_graphviz}) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 4d8a7e58e19fd..6ef38d07e45bb 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1600,7 +1600,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("check") .path("compiler") - .render_steps(), @"[check] rustc 0 -> rustc 1 (77 crates)"); + .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); } #[test] @@ -1626,7 +1626,7 @@ mod snapshot { ctx.config("check") .path("compiler") .stage(1) - .render_steps(), @"[check] rustc 0 -> rustc 1 (77 crates)"); + .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); } #[test] @@ -1640,7 +1640,7 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 (77 crates) + [check] rustc 1 -> rustc 2 (78 crates) "); } @@ -1656,7 +1656,7 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 [check] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 (77 crates) + [check] rustc 1 -> rustc 2 (78 crates) [check] rustc 1 -> rustc 2 [check] rustc 1 -> Rustdoc 2 [check] rustc 1 -> rustc_codegen_cranelift 2 @@ -1753,7 +1753,7 @@ mod snapshot { ctx.config("check") .paths(&["library", "compiler"]) .args(&args) - .render_steps(), @"[check] rustc 0 -> rustc 1 (77 crates)"); + .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); } #[test] @@ -2982,7 +2982,7 @@ mod snapshot { #[test] fn fix_compiler() { let ctx = TestCtx::new(); - insta::assert_snapshot!(ctx.config("fix").path("compiler").render_steps(), @"[fix] rustc 0 -> rustc 1 (77 crates)"); + insta::assert_snapshot!(ctx.config("fix").path("compiler").render_steps(), @"[fix] rustc 0 -> rustc 1 (78 crates)"); } }