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..5878de231badf --- /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, 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 + 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, 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 + 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 new file mode 100644 index 0000000000000..c3a3c7242901a --- /dev/null +++ b/tests/coverage/generic-unused-impl.coverage @@ -0,0 +1,18 @@ + LL| |// Regression test for #135235. + 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..8623138945006 --- /dev/null +++ b/tests/coverage/generic-unused-impl.rs @@ -0,0 +1,17 @@ +// Regression test for #135235. +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() {}