Skip to content

Commit 29de923

Browse files
author
Alexander Regueiro
committed
Account for diamond inheritance in vtable layout.
1 parent b183789 commit 29de923

File tree

8 files changed

+105
-71
lines changed

8 files changed

+105
-71
lines changed

src/librustc_codegen_ssa/base.rs

+5-4
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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1681,10 +1681,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16811681
exp_found: &ty::error::ExpectedFound<DefId>,
16821682
diag: &mut DiagnosticBuilder<'tcx>,
16831683
) {
1684-
use rustc::ty::{Binder, TraitRef};
1684+
use ty::{Binder, TraitRef};
16851685

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

src/librustc_infer/traits/util.rs

+34-4
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
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
@@ -123,7 +136,11 @@ pub fn elaborate_obligations<'tcx>(
123136
) -> Elaborator<'tcx> {
124137
let mut visited = PredicateSet::new(tcx);
125138
obligations.retain(|obligation| visited.insert(&obligation.predicate));
126-
Elaborator { stack: obligations, visited }
139+
Elaborator {
140+
stack: obligations,
141+
visited,
142+
allow_repetitions: false,
143+
}
127144
}
128145

129146
fn predicate_obligation<'tcx>(
@@ -134,7 +151,12 @@ fn predicate_obligation<'tcx>(
134151
if let Some(span) = span {
135152
cause.span = span;
136153
}
137-
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
154+
Obligation {
155+
cause,
156+
param_env: ty::ParamEnv::empty(),
157+
recursion_depth: 0,
158+
predicate,
159+
}
138160
}
139161

140162
impl Elaborator<'tcx> {
@@ -144,6 +166,7 @@ impl Elaborator<'tcx> {
144166

145167
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
146168
let tcx = self.visited.tcx;
169+
let allow_repetitions = self.allow_repetitions;
147170
match obligation.predicate {
148171
ty::Predicate::Trait(ref data, _) => {
149172
// Get predicates declared on the trait.
@@ -162,7 +185,7 @@ impl Elaborator<'tcx> {
162185
// cases. One common case is when people define
163186
// `trait Sized: Sized { }` rather than `trait Sized { }`.
164187
let visited = &mut self.visited;
165-
let obligations = obligations.filter(|o| visited.insert(&o.predicate));
188+
let obligations = obligations.filter(|o| allow_repetitions || visited.insert(&o.predicate));
166189

167190
self.stack.extend(obligations);
168191
}
@@ -245,7 +268,7 @@ impl Elaborator<'tcx> {
245268
None
246269
}
247270
})
248-
.filter(|p| visited.insert(p))
271+
.filter(|p| allow_repetitions || visited.insert(p))
249272
.map(|p| predicate_obligation(p, None)),
250273
);
251274
}
@@ -284,6 +307,13 @@ pub fn supertraits<'tcx>(
284307
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
285308
}
286309

310+
pub fn supertraits_with_repetitions<'tcx>(
311+
tcx: TyCtxt<'tcx>,
312+
trait_ref: ty::PolyTraitRef<'tcx>,
313+
) -> Supertraits<'tcx> {
314+
elaborate_trait_ref_with_repetitions(tcx, trait_ref).filter_to_traits()
315+
}
316+
287317
pub fn transitive_bounds<'tcx>(
288318
tcx: TyCtxt<'tcx>,
289319
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,

src/librustc_mir/interpret/traits.rs

+1-1
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

+2
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
889889
// Walk all methods of the trait, including those of its supertraits.
890890
let methods = tcx.vtable_methods(poly_trait_ref);
891891
let methods = methods
892+
.into_iter()
893+
.flat_map(|s| *s)
892894
.cloned()
893895
.filter_map(|method| method)
894896
.map(|(def_id, substs)| {

src/librustc_session/session.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,7 @@ impl Session {
474474
self.opts.debugging_opts.asm_comments
475475
}
476476
pub fn verify_llvm_ir(&self) -> bool {
477-
(self.opts.debugging_opts.verify_llvm_ir
478-
|| cfg!(always_verify_llvm_ir))
479-
&& !self.opts.debugging_opts.no_verify_llvm_ir
477+
self.opts.debugging_opts.verify_llvm_ir || cfg!(always_verify_llvm_ir)
480478
}
481479
pub fn borrowck_stats(&self) -> bool {
482480
self.opts.debugging_opts.borrowck_stats

src/librustc_trait_selection/traits/mod.rs

+46-44
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

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

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

0 commit comments

Comments
 (0)