Skip to content

Commit 3c45829

Browse files
author
Alexander Regueiro
committed
Account for diamond inheritance in vtable layout.
1 parent c4ae13b commit 3c45829

File tree

8 files changed

+105
-71
lines changed

8 files changed

+105
-71
lines changed

src/librustc_codegen_ssa/base.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ use rustc_middle::middle::cstore::EncodedMetadata;
3838
use rustc_middle::middle::cstore::{self, LinkagePreference};
3939
use rustc_middle::middle::lang_items;
4040
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
41+
use rustc_middle::traits::Vtable;
4142
use rustc_middle::ty::layout::{self, HasTyCtxt, TyAndLayout};
42-
use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
4343
use rustc_middle::ty::query::Providers;
4444
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
4545
use rustc_session::cgu_reuse_tracker::CguReuse;
@@ -166,7 +166,8 @@ pub fn unsized_info<'tcx, 'a, Bx: BuilderMethods<'a, 'tcx>>(
166166
let target_ptr = if let Some(target_trait_ref) = target_data.principal() {
167167
// Find the offset of the supertrait's vtable within the subtrait (parent) vtable.
168168
let trait_ref = target_trait_ref.with_self_ty(tcx, source);
169-
let vtable = tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref));
169+
let vtable = tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref))
170+
.unwrap_or_else(|| bug!("unsized_info: no vtable found"));
170171
let offset = match vtable {
171172
Vtable::VtableObject(ref data) => data.vtable_base,
172173
// HACK(alexreg): slightly dubious solution to ICE in
@@ -257,7 +258,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
257258
pub fn coerce_ptr_unsized<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
258259
bx: &mut Bx,
259260
op: OperandRef<'tcx, Bx::Value>,
260-
dst: TyLayout<'tcx>,
261+
dst: TyAndLayout<'tcx>,
261262
) -> OperandValue<Bx::Value> {
262263
assert!(bx.cx().is_backend_scalar_pair(dst));
263264
let src = op.layout;
@@ -341,7 +342,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
341342
(&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
342343
let src_op = bx.load_operand(src);
343344
let dst_op = coerce_ptr_unsized(bx, src_op, dst.layout);
344-
dst_op.store(bx, dst);s
345+
dst_op.store(bx, dst);
345346
}
346347
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
347348
assert_eq!(def_a, def_b);

src/librustc_infer/infer/error_reporting/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,10 +1679,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16791679
exp_found: &ty::error::ExpectedFound<DefId>,
16801680
diag: &mut DiagnosticBuilder<'tcx>,
16811681
) {
1682-
use rustc::ty::{Binder, TraitRef};
1682+
use ty::{Binder, TraitRef};
16831683

16841684
let trait_ref = Binder::bind(TraitRef::identity(self.tcx, exp_found.found));
1685-
let supertraits = crate::traits::supertraits(self.tcx, trait_ref);
1685+
let supertraits = crate::traits::util::supertraits(self.tcx, trait_ref);
16861686
if supertraits.into_iter().any(|trait_ref| trait_ref.def_id() == exp_found.expected) {
16871687
diag.note("add `#![feature(trait_upcasting)]` to the crate attributes to enable");
16881688
}

src/librustc_infer/traits/util.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> {
9191
pub struct Elaborator<'tcx> {
9292
stack: Vec<PredicateObligation<'tcx>>,
9393
visited: PredicateSet<'tcx>,
94+
/// `true` to allow the same predicate to appear more than once within the sequence.
95+
allow_repetitions: bool,
9496
}
9597

9698
pub fn elaborate_trait_ref<'tcx>(
@@ -108,6 +110,17 @@ pub fn elaborate_trait_refs<'tcx>(
108110
elaborate_predicates(tcx, predicates)
109111
}
110112

113+
pub fn elaborate_trait_ref_with_repetitions<'tcx>(
114+
tcx: TyCtxt<'tcx>,
115+
trait_ref: ty::PolyTraitRef<'tcx>,
116+
) -> Elaborator<'tcx> {
117+
Elaborator {
118+
stack: vec![predicate_obligation(trait_ref.without_const().to_predicate(), None)],
119+
visited: PredicateSet::new(tcx),
120+
allow_repetitions: true,
121+
}
122+
}
123+
111124
pub fn elaborate_predicates<'tcx>(
112125
tcx: TyCtxt<'tcx>,
113126
mut predicates: Vec<ty::Predicate<'tcx>>,
@@ -125,7 +138,11 @@ pub fn elaborate_obligations<'tcx>(
125138
) -> Elaborator<'tcx> {
126139
let mut visited = PredicateSet::new(tcx);
127140
obligations.retain(|obligation| visited.insert(&obligation.predicate));
128-
Elaborator { stack: obligations, visited }
141+
Elaborator {
142+
stack: obligations,
143+
visited,
144+
allow_repetitions: false,
145+
}
129146
}
130147

131148
fn predicate_obligation<'tcx>(
@@ -136,7 +153,12 @@ fn predicate_obligation<'tcx>(
136153
if let Some(span) = span {
137154
cause.span = span;
138155
}
139-
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
156+
Obligation {
157+
cause,
158+
param_env: ty::ParamEnv::empty(),
159+
recursion_depth: 0,
160+
predicate,
161+
}
140162
}
141163

142164
impl Elaborator<'tcx> {
@@ -146,6 +168,7 @@ impl Elaborator<'tcx> {
146168

147169
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
148170
let tcx = self.visited.tcx;
171+
let allow_repetitions = self.allow_repetitions;
149172
match obligation.predicate {
150173
ty::Predicate::Trait(ref data, _) => {
151174
// Get predicates declared on the trait.
@@ -165,7 +188,7 @@ impl Elaborator<'tcx> {
165188
// `trait Sized: Sized { }` rather than `trait Sized { }`.
166189
let visited = &mut self.visited;
167190
let obligations =
168-
obligations.filter(|obligation| visited.insert(&obligation.predicate));
191+
obligations.filter(|obligation| allow_repetitions || visited.insert(&obligation.predicate));
169192

170193
self.stack.extend(obligations);
171194
}
@@ -248,7 +271,7 @@ impl Elaborator<'tcx> {
248271
None
249272
}
250273
})
251-
.filter(|p| visited.insert(p))
274+
.filter(|p| allow_repetitions || visited.insert(p))
252275
.map(|p| predicate_obligation(p, None)),
253276
);
254277
}
@@ -287,6 +310,13 @@ pub fn supertraits<'tcx>(
287310
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
288311
}
289312

313+
pub fn supertraits_with_repetitions<'tcx>(
314+
tcx: TyCtxt<'tcx>,
315+
trait_ref: ty::PolyTraitRef<'tcx>,
316+
) -> Supertraits<'tcx> {
317+
elaborate_trait_ref_with_repetitions(tcx, trait_ref).filter_to_traits()
318+
}
319+
290320
pub fn transitive_bounds<'tcx>(
291321
tcx: TyCtxt<'tcx>,
292322
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,

src/librustc_mir/interpret/traits.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6161
ptr_size * (
6262
methods
6363
.iter()
64-
.map(|l| u64::try_from(methods.len()).unwrap().checked_add(3).unwrap())
64+
.map(|l| u64::try_from(l.len()).unwrap().checked_add(3).unwrap())
6565
.sum()
6666
),
6767
ptr_align,

src/librustc_mir/monomorphize/collector.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
885885
// Walk all methods of the trait, including those of its supertraits.
886886
let methods = tcx.vtable_methods(poly_trait_ref);
887887
let methods = methods
888+
.into_iter()
889+
.flat_map(|s| *s)
888890
.cloned()
889891
.filter_map(|method| method)
890892
.map(|(def_id, substs)| {

src/librustc_session/session.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,7 @@ impl Session {
429429
self.opts.debugging_opts.asm_comments
430430
}
431431
pub fn verify_llvm_ir(&self) -> bool {
432-
(self.opts.debugging_opts.verify_llvm_ir
433-
|| cfg!(always_verify_llvm_ir))
434-
&& !self.opts.debugging_opts.no_verify_llvm_ir
432+
self.opts.debugging_opts.verify_llvm_ir || cfg!(always_verify_llvm_ir)
435433
}
436434
pub fn borrowck_stats(&self) -> bool {
437435
self.opts.debugging_opts.borrowck_stats

src/librustc_trait_selection/traits/mod.rs

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub use self::util::{
6666
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
6767
};
6868
pub use self::util::{
69-
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
69+
supertraits, supertraits_with_repetitions, supertrait_def_ids, transitive_bounds, Supertraits,
70+
SupertraitDefIds,
7071
};
7172

7273
pub use rustc_infer::traits::*;
@@ -471,51 +472,52 @@ fn vtable_methods<'tcx>(
471472
) -> &'tcx [&'tcx [Option<(DefId, SubstsRef<'tcx>)>]] {
472473
debug!("vtable_methods({:?})", trait_ref);
473474

474-
tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).map(move |trait_ref| {
475-
let trait_methods = tcx
476-
.associated_items(trait_ref.def_id())
477-
.in_definition_order()
478-
.filter(|item| item.kind == ty::AssocKind::Fn);
479-
480-
// Now, list each method's `DefId` and `InternalSubsts` (for within its trait).
481-
// If the method can never be called from this object, produce `None`.
482-
&*tcx.arena.alloc_from_iter(trait_methods.map(move |trait_method| {
483-
debug!("vtable_methods: trait_method={:?}", trait_method);
484-
let def_id = trait_method.def_id;
485-
486-
// Some methods cannot be called on an object; skip those.
487-
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
488-
debug!("vtable_methods: not vtable safe");
489-
return None;
490-
}
475+
tcx.arena.alloc_from_iter(supertraits_with_repetitions(tcx, trait_ref)
476+
.map(move |trait_ref| {
477+
let trait_methods = tcx
478+
.associated_items(trait_ref.def_id())
479+
.in_definition_order()
480+
.filter(|item| item.kind == ty::AssocKind::Fn);
481+
482+
// Now, list each method's `DefId` and `InternalSubsts` (for within its trait).
483+
// If the method can never be called from this object, produce `None`.
484+
&*tcx.arena.alloc_from_iter(trait_methods.map(move |trait_method| {
485+
debug!("vtable_methods: trait_method={:?}", trait_method);
486+
let def_id = trait_method.def_id;
487+
488+
// Some methods cannot be called on an object; skip those.
489+
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
490+
debug!("vtable_methods: not vtable safe");
491+
return None;
492+
}
491493

492-
// The method may have some early-bound lifetimes; add regions for those.
493-
let substs = trait_ref.map_bound(|trait_ref| {
494-
InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
495-
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
496-
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
497-
trait_ref.substs[param.index as usize]
498-
}
499-
})
500-
});
501-
502-
// The trait type may have higher-ranked lifetimes in it;
503-
// erase them if they appear, so that we get the type
504-
// at some particular call site.
505-
let substs =
506-
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);
507-
508-
// It's possible that the method relies on where-clauses that
509-
// do not hold for this particular set of type parameters.
510-
// Note that this method could then never be called, so we
511-
// do not want to try and codegen it, in that case (see #23435).
512-
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
513-
if !normalize_and_test_predicates(tcx, predicates.predicates) {
514-
debug!("vtable_methods: predicates do not hold");
515-
return None;
516-
}
494+
// The method may have some early-bound lifetimes; add regions for those.
495+
let substs = trait_ref.map_bound(|trait_ref| {
496+
InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
497+
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
498+
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
499+
trait_ref.substs[param.index as usize]
500+
}
501+
})
502+
});
503+
504+
// The trait type may have higher-ranked lifetimes in it;
505+
// erase them if they appear, so that we get the type
506+
// at some particular call site.
507+
let substs =
508+
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);
509+
510+
// It's possible that the method relies on where-clauses that
511+
// do not hold for this particular set of type parameters.
512+
// Note that this method could then never be called, so we
513+
// do not want to try and codegen it, in that case (see #23435).
514+
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
515+
if !normalize_and_test_predicates(tcx, predicates.predicates) {
516+
debug!("vtable_methods: predicates do not hold");
517+
return None;
518+
}
517519

518-
Some((def_id, substs))
520+
Some((def_id, substs))
519521
}))
520522
}))
521523
}

src/librustc_trait_selection/traits/select.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,26 +2695,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
26952695
// where we can unify, because otherwise select would have
26962696
// reported an ambiguity. (When we do find a match, also
26972697
// record it for later.)
2698-
let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| {
2699-
match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
2700-
Ok(obligations) => {
2701-
upcast_trait_ref = Some(t);
2702-
nested.extend(obligations);
2703-
false
2704-
}
2705-
Err(_) => true,
2706-
}
2707-
});
2698+
let nonmatching = util::supertraits_with_repetitions(tcx, poly_trait_ref)
2699+
.take_while(
2700+
|&trait_ref| match self.infcx.commit_if_ok(
2701+
|_| self.match_poly_trait_ref(obligation, trait_ref)
2702+
) {
2703+
Ok(obligations) => {
2704+
upcast_trait_ref = Some(trait_ref);
2705+
nested.extend(obligations);
2706+
false
2707+
}
2708+
Err(_) => true,
2709+
},
2710+
);
27082711

27092712
// Additionally, for each of the non-matching predicates that
27102713
// we pass over, we sum up the set of number of vtable
27112714
// entries, so that we can compute the offset for the selected
27122715
// trait.
27132716
vtable_base = nonmatching
27142717
// Skip 3 entries in vtable per supertrait for `(drop, size, align)` metadata.
2715-
.map(|trait_ref|
2716-
u64::try_from(tcx.count_own_vtable_entries(trait_ref)).unwrap().checked_add(3).unwrap()
2717-
)
2718+
.map(|trait_ref| util::count_own_vtable_entries(tcx, trait_ref).checked_add(3).unwrap())
27182719
.sum();
27192720
}
27202721

0 commit comments

Comments
 (0)