Skip to content

Commit

Permalink
Rollup merge of rust-lang#135261 - compiler-errors:coverage-has-ident…
Browse files Browse the repository at this point in the history
…ity-substs, r=oli-obk

Account for identity substituted items in symbol mangling

See the inline comment.

r? oli-obk

Fixes rust-lang#135235
  • Loading branch information
matthiaskrgr authored Jan 9, 2025
2 parents 8ff355a + b85b2c6 commit 41c7d5a
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 39 deletions.
12 changes: 8 additions & 4 deletions compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
})
}
}

Expand Down
56 changes: 38 additions & 18 deletions compiler/rustc_symbol_mangling/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 `<Ty as Trait>::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<A> Tr<A> 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) => {
Expand Down
55 changes: 38 additions & 17 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<Ty as Trait>::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<A> Tr<A> 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) => {
Expand Down
18 changes: 18 additions & 0 deletions tests/coverage/generic-unused-impl.cov-map
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Function name: <generic_unused_impl::W<_> 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

18 changes: 18 additions & 0 deletions tests/coverage/generic-unused-impl.coverage
Original file line number Diff line number Diff line change
@@ -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>(T);
LL| |
LL| |impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
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() {}

17 changes: 17 additions & 0 deletions tests/coverage/generic-unused-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Regression test for #135235.
trait Foo {
type Assoc;

fn from(s: Self::Assoc) -> Self;
}

struct W<T>(T);

impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
fn from(from: [T::Assoc; 1]) -> Self {
let [item] = from;
W(Foo::from(item))
}
}

fn main() {}

0 comments on commit 41c7d5a

Please sign in to comment.