Rollup merge of #135149 - compiler-errors:mangle, r=oli-obk
Use a post-monomorphization typing env when mangling components that come from impls When mangling associated methods of impls, we were previously using the wrong param-env. Instead of using a fully monomorphized param-env like we usually do in codegen, we were taking the post-analysis param-env, and treating it as an early binder to *re-substitute* the impl args. I've pointed out the problematic old code in an inline comment. This would give us param-envs with possibly trivial predicates that would prevent normalization via param-env shadowing. In the example test linked below, `tests/ui/symbol-names/normalize-in-param-env.rs`, this happens when we mangle the impl `impl<P: Point2> MyFrom<P::S> for P` with the substitution `P = Vec2`. Because the where clause of the impl is `P: Point2`, which elaborates to `[P: Point2, P: Point, <P as Point>::S projects-to <P as Point2>::S2]` and the fact that `impl Point2 for Vec2` normalizes `Vec2::S2` to `Vec2::S`, this causes a cycle. The proper fix here is to use a fully monomorphized param-env for the case where the impl is properly substituted. Fixes #135143 While #134081 uncovered this bug for legacy symbol mangling, it was preexisting for v0 symbol mangling. This PR fixes both. The test requires a "hack" because we strip the args of the instance we're printing for legacy symbol mangling except for drop glue, so we box a closure to ensure we generate drop glue. r? oli-obk
This commit is contained in:
commit
3e12d4d152
4 changed files with 99 additions and 38 deletions
|
@ -45,10 +45,25 @@ pub trait Printer<'tcx>: Sized {
|
||||||
&mut self,
|
&mut self,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
args: &'tcx [GenericArg<'tcx>],
|
args: &'tcx [GenericArg<'tcx>],
|
||||||
self_ty: Ty<'tcx>,
|
|
||||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
|
||||||
) -> Result<(), PrintError> {
|
) -> Result<(), PrintError> {
|
||||||
self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref)
|
let tcx = self.tcx();
|
||||||
|
let self_ty = tcx.type_of(impl_def_id);
|
||||||
|
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||||
|
let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
|
||||||
|
(
|
||||||
|
self_ty.instantiate(tcx, args),
|
||||||
|
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// We are probably printing a nested item inside of an impl.
|
||||||
|
// Use the identity substitutions for the impl.
|
||||||
|
(
|
||||||
|
self_ty.instantiate_identity(),
|
||||||
|
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
|
fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
|
||||||
|
@ -107,23 +122,7 @@ pub trait Printer<'tcx>: Sized {
|
||||||
self.path_crate(def_id.krate)
|
self.path_crate(def_id.krate)
|
||||||
}
|
}
|
||||||
|
|
||||||
DefPathData::Impl => {
|
DefPathData::Impl => self.print_impl_path(def_id, args),
|
||||||
let generics = self.tcx().generics_of(def_id);
|
|
||||||
let self_ty = self.tcx().type_of(def_id);
|
|
||||||
let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
|
|
||||||
let (self_ty, impl_trait_ref) = if args.len() >= generics.count() {
|
|
||||||
(
|
|
||||||
self_ty.instantiate(self.tcx(), args),
|
|
||||||
impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
self_ty.instantiate_identity(),
|
|
||||||
impl_trait_ref.map(|i| i.instantiate_identity()),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
self.print_impl_path(def_id, args, self_ty, impl_trait_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
|
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
|
||||||
|
@ -201,7 +200,6 @@ pub trait Printer<'tcx>: Sized {
|
||||||
fn default_print_impl_path(
|
fn default_print_impl_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
_args: &'tcx [GenericArg<'tcx>],
|
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||||
) -> Result<(), PrintError> {
|
) -> Result<(), PrintError> {
|
||||||
|
|
|
@ -8,6 +8,7 @@ use rustc_middle::bug;
|
||||||
use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
|
use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
|
self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
|
||||||
|
TypingEnv,
|
||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -383,14 +384,26 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
args: &'tcx [GenericArg<'tcx>],
|
args: &'tcx [GenericArg<'tcx>],
|
||||||
mut self_ty: Ty<'tcx>,
|
|
||||||
mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
|
||||||
) -> Result<(), PrintError> {
|
) -> Result<(), PrintError> {
|
||||||
let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
|
let self_ty = self.tcx.type_of(impl_def_id);
|
||||||
if !args.is_empty() {
|
let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
|
||||||
typing_env.param_env =
|
let (typing_env, mut self_ty, mut impl_trait_ref) =
|
||||||
ty::EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
|
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()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
match &mut impl_trait_ref {
|
match &mut impl_trait_ref {
|
||||||
Some(impl_trait_ref) => {
|
Some(impl_trait_ref) => {
|
||||||
|
@ -403,7 +416,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.default_print_impl_path(impl_def_id, args, self_ty, impl_trait_ref)
|
self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ use rustc_middle::bug;
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
use rustc_middle::ty::print::{Print, PrintError, Printer};
|
use rustc_middle::ty::print::{Print, PrintError, Printer};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, EarlyBinder, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty,
|
self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
|
||||||
TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
|
TypeVisitable, TypeVisitableExt, UintTy,
|
||||||
};
|
};
|
||||||
use rustc_span::kw;
|
use rustc_span::kw;
|
||||||
|
|
||||||
|
@ -227,17 +227,29 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
args: &'tcx [GenericArg<'tcx>],
|
args: &'tcx [GenericArg<'tcx>],
|
||||||
mut self_ty: Ty<'tcx>,
|
|
||||||
mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
|
||||||
) -> Result<(), PrintError> {
|
) -> Result<(), PrintError> {
|
||||||
let key = self.tcx.def_key(impl_def_id);
|
let key = self.tcx.def_key(impl_def_id);
|
||||||
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
|
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
|
||||||
|
|
||||||
let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
|
let self_ty = self.tcx.type_of(impl_def_id);
|
||||||
if !args.is_empty() {
|
let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
|
||||||
typing_env.param_env =
|
let (typing_env, mut self_ty, mut impl_trait_ref) =
|
||||||
EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
|
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()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
match &mut impl_trait_ref {
|
match &mut impl_trait_ref {
|
||||||
Some(impl_trait_ref) => {
|
Some(impl_trait_ref) => {
|
||||||
|
|
38
tests/ui/symbol-names/normalize-in-param-env.rs
Normal file
38
tests/ui/symbol-names/normalize-in-param-env.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//@ revisions: legacy v0
|
||||||
|
//@[v0] compile-flags: -C symbol-mangling-version=v0
|
||||||
|
//@[legacy] compile-flags: -C symbol-mangling-version=legacy -Zunstable-options
|
||||||
|
//@ build-pass
|
||||||
|
|
||||||
|
pub struct Vec2;
|
||||||
|
|
||||||
|
pub trait Point {
|
||||||
|
type S;
|
||||||
|
}
|
||||||
|
impl Point for Vec2 {
|
||||||
|
type S = f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Point2: Point<S = Self::S2> {
|
||||||
|
type S2;
|
||||||
|
}
|
||||||
|
impl Point2 for Vec2 {
|
||||||
|
type S2 = Self::S;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MyFrom<T> {
|
||||||
|
fn my_from();
|
||||||
|
}
|
||||||
|
impl<P: Point2> MyFrom<P::S> for P {
|
||||||
|
fn my_from() {
|
||||||
|
// This is just a really dumb way to force the legacy symbol mangling to
|
||||||
|
// mangle the closure's parent impl def path *with* args. Otherwise,
|
||||||
|
// legacy symbol mangling will strip the args from the instance, meaning
|
||||||
|
// that we don't trigger the bug.
|
||||||
|
let c = || {};
|
||||||
|
let x = Box::new(c) as Box<dyn Fn()>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
<Vec2 as MyFrom<_>>::my_from();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue