From 39daadc76ebdb97e0acf242791be129ae1003e16 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 8 Jan 2025 17:31:40 +0000 Subject: [PATCH 1/2] Account for identity substituted items in symbol mangling --- .../src/ty/normalize_erasing_regions.rs | 12 ++-- compiler/rustc_symbol_mangling/src/legacy.rs | 56 +++++++++++++------ compiler/rustc_symbol_mangling/src/v0.rs | 55 ++++++++++++------ tests/coverage/generic-unused-impl.cov-map | 18 ++++++ tests/coverage/generic-unused-impl.coverage | 17 ++++++ tests/coverage/generic-unused-impl.rs | 16 ++++++ 6 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 tests/coverage/generic-unused-impl.cov-map create mode 100644 tests/coverage/generic-unused-impl.coverage create mode 100644 tests/coverage/generic-unused-impl.rs diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index f611b69905c9c..e86e01451fefb 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -165,10 +165,14 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.typing_env.as_query_input(arg); - self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( - "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", - arg.value - )) + self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| { + bug!( + "Failed to normalize {:?} in typing_env={:?}, \ + maybe try to call `try_normalize_erasing_regions` instead", + arg.value, + self.typing_env, + ) + }) } } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 333ea0214eb3f..58c0a05df1f2c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -8,7 +8,6 @@ use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt, - TypingEnv, }; use tracing::debug; @@ -387,23 +386,44 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result<(), PrintError> { let self_ty = self.tcx.type_of(impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); - let (typing_env, mut self_ty, mut impl_trait_ref) = - if self.tcx.generics_of(impl_def_id).count() <= args.len() { - ( - TypingEnv::fully_monomorphized(), - self_ty.instantiate(self.tcx, args), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), - ) - } else { - // We are probably printing a nested item inside of an impl. - // Use the identity substitutions for the impl. We also need - // a well-formed param-env, so let's use post-analysis. - ( - TypingEnv::post_analysis(self.tcx, impl_def_id), - self_ty.instantiate_identity(), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), - ) - }; + let generics = self.tcx.generics_of(impl_def_id); + // We have two cases to worry about here: + // 1. We're printing a nested item inside of an impl item, like an inner + // function inside of a method. Due to the way that def path printing works, + // we'll render this something like `::method::inner_fn` + // but we have no substs for this impl since it's not really inheriting + // generics from the outer item. We need to use the identity substs, and + // to normalize we need to use the correct param-env too. + // 2. We're mangling an item with identity substs. This seems to only happen + // when generating coverage, since we try to generate coverage for unused + // items too, and if something isn't monomorphized then we necessarily don't + // have anything to substitute the instance with. + // NOTE: We don't support mangling partially substituted but still polymorphic + // instances, like `impl Tr for ()` where `A` is substituted w/ `(T,)`. + let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len() + || &args[..generics.count()] + == self + .tcx + .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .as_slice() + { + ( + ty::TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + } else { + assert!( + !args.has_non_region_param(), + "should not be mangling partially substituted \ + polymorphic instance: {impl_def_id:?} {args:?}" + ); + ( + ty::TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index b77ad209e2bd8..4ddf530a00d4a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -233,23 +233,44 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let self_ty = self.tcx.type_of(impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); - let (typing_env, mut self_ty, mut impl_trait_ref) = - if self.tcx.generics_of(impl_def_id).count() <= args.len() { - ( - ty::TypingEnv::fully_monomorphized(), - self_ty.instantiate(self.tcx, args), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), - ) - } else { - // We are probably printing a nested item inside of an impl. - // Use the identity substitutions for the impl. We also need - // a well-formed param-env, so let's use post-analysis. - ( - ty::TypingEnv::post_analysis(self.tcx, impl_def_id), - self_ty.instantiate_identity(), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), - ) - }; + let generics = self.tcx.generics_of(impl_def_id); + // We have two cases to worry about here: + // 1. We're printing a nested item inside of an impl item, like an inner + // function inside of a method. Due to the way that def path printing works, + // we'll render this something like `::method::inner_fn` + // but we have no substs for this impl since it's not really inheriting + // generics from the outer item. We need to use the identity substs, and + // to normalize we need to use the correct param-env too. + // 2. We're mangling an item with identity substs. This seems to only happen + // when generating coverage, since we try to generate coverage for unused + // items too, and if something isn't monomorphized then we necessarily don't + // have anything to substitute the instance with. + // NOTE: We don't support mangling partially substituted but still polymorphic + // instances, like `impl Tr for ()` where `A` is substituted w/ `(T,)`. + let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len() + || &args[..generics.count()] + == self + .tcx + .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .as_slice() + { + ( + ty::TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + } else { + assert!( + !args.has_non_region_param(), + "should not be mangling partially substituted \ + polymorphic instance: {impl_def_id:?} {args:?}" + ); + ( + ty::TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map new file mode 100644 index 0000000000000..7cb6d2f385d79 --- /dev/null +++ b/tests/coverage/generic-unused-impl.cov-map @@ -0,0 +1,18 @@ +Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0a, 05, 03, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 10, 5) to (start + 3, 6) +Highest counter ID seen: (none) + +Function name: generic_unused_impl::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 00, 0d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage new file mode 100644 index 0000000000000..0c20285f84544 --- /dev/null +++ b/tests/coverage/generic-unused-impl.coverage @@ -0,0 +1,17 @@ + LL| |trait Foo { + LL| | type Assoc; + LL| | + LL| | fn from(s: Self::Assoc) -> Self; + LL| |} + LL| | + LL| |struct W(T); + LL| | + LL| |impl From<[T::Assoc; 1]> for W { + LL| 0| fn from(from: [T::Assoc; 1]) -> Self { + LL| 0| let [item] = from; + LL| 0| W(Foo::from(item)) + LL| 0| } + LL| |} + LL| | + LL| 1|fn main() {} + diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs new file mode 100644 index 0000000000000..e44b1ca8a1d74 --- /dev/null +++ b/tests/coverage/generic-unused-impl.rs @@ -0,0 +1,16 @@ +trait Foo { + type Assoc; + + fn from(s: Self::Assoc) -> Self; +} + +struct W(T); + +impl From<[T::Assoc; 1]> for W { + fn from(from: [T::Assoc; 1]) -> Self { + let [item] = from; + W(Foo::from(item)) + } +} + +fn main() {} From b85b2c60f950252d38ce91b0f1ab535333866b3b Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 9 Jan 2025 13:24:16 +0100 Subject: [PATCH 2/2] add comment to test --- tests/coverage/generic-unused-impl.cov-map | 8 ++++---- tests/coverage/generic-unused-impl.coverage | 1 + tests/coverage/generic-unused-impl.rs | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map index 7cb6d2f385d79..5878de231badf 100644 --- a/tests/coverage/generic-unused-impl.cov-map +++ b/tests/coverage/generic-unused-impl.cov-map @@ -1,18 +1,18 @@ Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0a, 05, 03, 06] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 10, 5) to (start + 3, 6) +- Code(Zero) at (prev + 11, 5) to (start + 3, 6) Highest counter ID seen: (none) Function name: generic_unused_impl::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 00, 0d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage index 0c20285f84544..c3a3c7242901a 100644 --- a/tests/coverage/generic-unused-impl.coverage +++ b/tests/coverage/generic-unused-impl.coverage @@ -1,3 +1,4 @@ + LL| |// Regression test for #135235. LL| |trait Foo { LL| | type Assoc; LL| | diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs index e44b1ca8a1d74..8623138945006 100644 --- a/tests/coverage/generic-unused-impl.rs +++ b/tests/coverage/generic-unused-impl.rs @@ -1,3 +1,4 @@ +// Regression test for #135235. trait Foo { type Assoc;