Skip to content

Commit

Permalink
Do not treat vtable supertraits as distinct when bound with different…
Browse files Browse the repository at this point in the history
… bound vars
  • Loading branch information
compiler-errors committed Jan 10, 2025
1 parent 8247594 commit ed4c92f
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 116 deletions.
7 changes: 6 additions & 1 deletion compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,12 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc = self
.tcx
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
.global_alloc(self.tcx.vtable_allocation((
ty,
dyn_ty.principal().map(|principal| {
self.tcx.instantiate_bound_regions_with_erased(principal)
}),
)))
.unwrap_memory();
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
let value = self.static_addr_of(init, alloc.inner().align, None);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1406,7 +1406,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(

let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
let trait_ref = tcx.erase_regions(trait_ref);
let trait_ref = tcx.erase_regions(tcx.instantiate_bound_regions_with_erased(trait_ref));

tcx.vtable_entries(trait_ref)
} else {
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_codegen_ssa/src/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,28 @@ fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
cx: &Cx,
ty: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Cx::Value {
let tcx = cx.tcx();

// Check the cache.
if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
if let Some(&val) = cx.vtables().borrow().get(&(ty, poly_trait_ref)) {
return val;
}

// FIXME(trait_upcasting): Take a non-higher-ranked vtable as arg.
let trait_ref =
poly_trait_ref.map(|trait_ref| tcx.instantiate_bound_regions_with_erased(trait_ref));

let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
let vtable_const = cx.const_data_from_alloc(vtable_allocation);
let align = cx.data_layout().pointer_align.abi;
let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));

cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
cx.create_vtable_debuginfo(ty, trait_ref, vtable);
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
cx.apply_vcall_visibility_metadata(ty, poly_trait_ref, vtable);
cx.create_vtable_debuginfo(ty, poly_trait_ref, vtable);
cx.vtables().borrow_mut().insert((ty, poly_trait_ref), vtable);
vtable
}

Expand Down
10 changes: 1 addition & 9 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
if let Some(entry_idx) = vptr_entry_idx {
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
vtable_entries.get(entry_idx)
let Some(&ty::VtblEntry::TraitVPtr(_)) = vtable_entries.get(entry_idx)
else {
span_bug!(
self.cur_span(),
Expand All @@ -429,13 +428,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
dest_pointee_ty
);
};
let erased_trait_ref = upcast_trait_ref
.map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r));
assert!(
data_b
.principal()
.is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b))
);
} else {
// In this case codegen would keep using the old vtable. We don't want to do
// that as it has the wrong trait. The reason codegen can do this is that
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> &'tcx [VtblEntry<'tcx>] {
if let Some(trait_) = trait_ {
let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
let trait_ref = self.tcx.erase_regions(trait_ref);
let trait_ref =
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
self.tcx.vtable_entries(trait_ref)
} else {
TyCtxt::COMMON_VTABLE_ENTRIES
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
// Number of vtable entries needed solely for upcasting
let mut entries_for_upcasting = 0;

let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
let trait_ref = ty::TraitRef::identity(tcx, tr);

// A slightly edited version of the code in
// `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self
Expand Down Expand Up @@ -1041,7 +1041,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
// Lookup the shape of vtable for the trait.
let own_existential_entries =
tcx.own_existential_vtable_entries(trait_ref.def_id());
tcx.own_existential_vtable_entries(trait_ref.def_id);

// The original code here ignores the method if its predicates are
// impossible. We can't really do that as, for example, all not trivial
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
}
}

impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
impl<'tcx> Key for (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>) {
type Cache<V> = DefaultCache<Self, V>;

fn default_span(&self, _: TyCtxt<'_>) -> Span {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1435,9 +1435,9 @@ rustc_queries! {
desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
}

query vtable_entries(key: ty::PolyTraitRef<'tcx>)
query vtable_entries(key: ty::TraitRef<'tcx>)
-> &'tcx [ty::VtblEntry<'tcx>] {
desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id) }
}

query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize {
Expand All @@ -1449,7 +1449,7 @@ rustc_queries! {
key.1, key.0 }
}

query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
query vtable_allocation(key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
desc { |tcx| "vtable const allocation for <{} as {}>",
key.0,
key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned())
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,12 @@ where
}

let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
let min_count = ty::vtable_min_entries(tcx, principal);
let min_count = ty::vtable_min_entries(
tcx,
principal.map(|principal| {
tcx.instantiate_bound_regions_with_erased(principal)
}),
);
Ty::new_imm_ref(
tcx,
tcx.lifetimes.re_static,
Expand Down
17 changes: 8 additions & 9 deletions compiler/rustc_middle/src/ty/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_ast::Mutability;
use rustc_macros::HashStable;

use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt};

#[derive(Clone, Copy, PartialEq, HashStable)]
pub enum VtblEntry<'tcx> {
Expand All @@ -19,7 +19,7 @@ pub enum VtblEntry<'tcx> {
/// dispatchable associated function
Method(Instance<'tcx>),
/// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
TraitVPtr(PolyTraitRef<'tcx>),
TraitVPtr(TraitRef<'tcx>),
}

impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
Expand Down Expand Up @@ -56,15 +56,15 @@ pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
// function is an accurate approximation. We verify this when actually computing the vtable below.
pub(crate) fn vtable_min_entries<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
) -> usize {
let mut count = TyCtxt::COMMON_VTABLE_ENTRIES.len();
let Some(trait_ref) = trait_ref else {
return count;
};

// This includes self in supertraits.
for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) {
for def_id in tcx.supertrait_def_ids(trait_ref.def_id) {
count += tcx.own_existential_vtable_entries(def_id).len();
}

Expand All @@ -80,7 +80,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
/// initial contents.)
pub(super) fn vtable_allocation_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>),
) -> AllocId {
let (ty, poly_trait_ref) = key;

Expand Down Expand Up @@ -115,7 +115,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(

for (idx, entry) in vtable_entries.iter().enumerate() {
let idx: u64 = u64::try_from(idx).unwrap();
let scalar = match entry {
let scalar = match *entry {
VtblEntry::MetadataDropInPlace => {
if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) {
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
Expand All @@ -131,13 +131,12 @@ pub(super) fn vtable_allocation_provider<'tcx>(
VtblEntry::Vacant => continue,
VtblEntry::Method(instance) => {
// Prepare the fn ptr we write into the vtable.
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT);
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
let fn_ptr = Pointer::from(fn_alloc_id);
Scalar::from_pointer(fn_ptr, &tcx)
}
VtblEntry::TraitVPtr(trait_ref) => {
let super_trait_ref = trait_ref
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
let super_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref)));
let vptr = Pointer::from(supertrait_alloc_id);
Scalar::from_pointer(vptr, &tcx)
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,11 +1129,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type");
};
if let Some(principal) = trait_ty.principal() {
let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
assert!(!poly_trait_ref.has_escaping_bound_vars());
let trait_ref =
tcx.instantiate_bound_regions_with_erased(principal.with_self_ty(tcx, impl_ty));
assert!(!trait_ref.has_escaping_bound_vars());

// Walk all methods of the trait, including those of its supertraits
let entries = tcx.vtable_entries(poly_trait_ref);
let entries = tcx.vtable_entries(trait_ref);
debug!(?entries);
let methods = entries
.iter()
Expand Down Expand Up @@ -1188,7 +1189,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
}
}
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal()));
let alloc_id = tcx.vtable_allocation((
ty,
dyn_ty
.principal()
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
));
collect_alloc(tcx, alloc_id, output)
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_smir/src/rustc_smir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
let tcx = tables.tcx;
let alloc_id = tables.tcx.vtable_allocation((
ty.internal(&mut *tables, tcx),
trait_ref.internal(&mut *tables, tcx),
trait_ref
.internal(&mut *tables, tcx)
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
));
Some(alloc_id.stable(&mut *tables))
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{FnRetTy, GenericParamKind, Node};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt};
use rustc_span::{BytePos, Ident, Span, Symbol, kw};

use crate::error_reporting::infer::ObligationCauseAsDiagArg;
Expand All @@ -28,7 +28,7 @@ pub mod note_and_explain;
pub struct DumpVTableEntries<'a> {
#[primary_span]
pub span: Span,
pub trait_ref: PolyTraitRef<'a>,
pub trait_ref: ty::TraitRef<'a>,
pub entries: String,
}

Expand Down
Loading

0 comments on commit ed4c92f

Please sign in to comment.