Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Prev Previous commit
Ran rustfmt.
  • Loading branch information
Alexander Regueiro committed May 5, 2020
commit 041cbfb0f20db5e7f3e99f787ead05bff9dbcd18
37 changes: 15 additions & 22 deletions src/librustc_codegen_ssa/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ pub fn unsized_info<'tcx, 'a, Bx: BuilderMethods<'a, 'tcx>>(
let target_ptr = if let Some(target_trait_ref) = target_data.principal() {
// Find the offset of the supertrait's vtable within the subtrait (parent) vtable.
let trait_ref = target_trait_ref.with_self_ty(tcx, source);
let vtable = tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref))
let vtable = tcx
.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref))
.unwrap_or_else(|| bug!("unsized_info: vtable not found"));
let offset = match vtable {
Vtable::VtableObject(ref data) => data.vtable_base,
Expand Down Expand Up @@ -271,19 +272,14 @@ pub fn coerce_ptr_unsized<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// existing vtable. See the `get_vtable` fn in `meth.rs` for more details of vtable
// layout.

let base = bx.pointercast(
base,
bx.cx().scalar_pair_element_backend_type(dst, 0, true),
);
let base = bx.pointercast(base, bx.cx().scalar_pair_element_backend_type(dst, 0, true));
let info = match (&src.ty.kind, &dst.ty.kind) {
(&ty::Ref(_, a, _),
&ty::Ref(_, b, _)) |
(&ty::Ref(_, a, _),
&ty::RawPtr(ty::TypeAndMut { ty: b, .. })) |
(&ty::RawPtr(ty::TypeAndMut { ty: a, .. }),
&ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
unsized_info(bx, a, b, Some(info))
}
(&ty::Ref(_, a, _), &ty::Ref(_, b, _))
| (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
| (
&ty::RawPtr(ty::TypeAndMut { ty: a, .. }),
&ty::RawPtr(ty::TypeAndMut { ty: b, .. }),
) => unsized_info(bx, a, b, Some(info)),
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);

Expand Down Expand Up @@ -313,17 +309,14 @@ pub fn coerce_ptr_unsized<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
// FIXME(eddyb) move these out of this `match` arm, so they're always
// applied, uniformly, no matter the source/destination types.
(bx.bitcast(base, bx.cx().scalar_pair_element_backend_type(dst, 0, true)),
bx.bitcast(info, bx.cx().scalar_pair_element_backend_type(dst, 1, true)))
}
OperandValue::Immediate(base) => {
unsize_thin_ptr(bx, base, src.ty, dst.ty)
(
bx.bitcast(base, bx.cx().scalar_pair_element_backend_type(dst, 0, true)),
bx.bitcast(info, bx.cx().scalar_pair_element_backend_type(dst, 1, true)),
)
}
OperandValue::Immediate(base) => unsize_thin_ptr(bx, base, src.ty, dst.ty),
OperandValue::Ref(..) => {
bug!(
"coerce_ptr_unsized: unexpected by-ref operand {:?}",
op
);
bug!("coerce_ptr_unsized: unexpected by-ref operand {:?}", op);
}
};
OperandValue::Pair(base, info)
Expand Down
7 changes: 3 additions & 4 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,9 +1591,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);

if let &TypeError::Traits(ref exp_found_traits) = terr {
self.note_enable_trait_upcasting_where_appropriate(
&exp_found_traits, diag
);
self.note_enable_trait_upcasting_where_appropriate(&exp_found_traits, diag);
}
}

Expand Down Expand Up @@ -1688,7 +1686,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if supertraits.into_iter().any(|trait_ref| trait_ref.def_id() == exp_found.expected) {
diag.note(
"add `#![feature(trait_upcasting)]` to the crate attributes to enable \
trait upcasting");
trait upcasting",
);
}
}

Expand Down
16 changes: 4 additions & 12 deletions src/librustc_infer/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,7 @@ pub fn elaborate_obligations<'tcx>(
) -> Elaborator<'tcx> {
let mut visited = PredicateSet::new(tcx);
obligations.retain(|obligation| visited.insert(&obligation.predicate));
Elaborator {
stack: obligations,
visited,
allow_repetitions: false,
}
Elaborator { stack: obligations, visited, allow_repetitions: false }
}

fn predicate_obligation<'tcx>(
Expand All @@ -151,12 +147,7 @@ fn predicate_obligation<'tcx>(
if let Some(span) = span {
cause.span = span;
}
Obligation {
cause,
param_env: ty::ParamEnv::empty(),
recursion_depth: 0,
predicate,
}
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
}

impl Elaborator<'tcx> {
Expand Down Expand Up @@ -185,7 +176,8 @@ impl Elaborator<'tcx> {
// cases. One common case is when people define
// `trait Sized: Sized { }` rather than `trait Sized { }`.
let visited = &mut self.visited;
let obligations = obligations.filter(|o| allow_repetitions || visited.insert(&o.predicate));
let obligations =
obligations.filter(|o| allow_repetitions || visited.insert(&o.predicate));

self.stack.extend(obligations);
}
Expand Down
11 changes: 4 additions & 7 deletions src/librustc_mir/interpret/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let vtable = self.memory.allocate(
// Compute size of vtable, including 3 entries per supertrait for (drop, size, align)
// metadata.
ptr_size * (
methods
ptr_size
* (methods
.iter()
.map(|l| u64::try_from(l.len()).unwrap().checked_add(3).unwrap())
.sum()
),
.sum()),
ptr_align,
MemoryKind::Vtable,
);
Expand All @@ -73,9 +72,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// one pointer size each time.
let mut cur_ptr = vtable;
let mut write_ptr = |memory: &mut Memory<'mir, 'tcx, M>, val| -> InterpResult<'_> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is the layout of vtables documented anywhere? I'd love to see it in the rustc-guide or source (cc @oli-obk, @eddyb)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(People are inevitably going to look at that to make assumptions about it in unsafe code. Imo we should add disclaimers that the layout is unstable -- I know that's "always true of repr(Rust)" but trait objects seem to invite more assuming than usual.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move all the logic of vtables to a single module and add some docs on the module explaining what is going on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's probably sensible, but best done in a separate follow-up PR (this one is big enough as-is).

let res = memory
.get_raw_mut(cur_ptr.alloc_id)?
.write_ptr_sized(tcx, cur_ptr, val)?;
let res = memory.get_raw_mut(cur_ptr.alloc_id)?.write_ptr_sized(tcx, cur_ptr, val)?;
cur_ptr = cur_ptr.offset(ptr_size, tcx)?;
Ok(res)
};
Expand Down
91 changes: 45 additions & 46 deletions src/librustc_trait_selection/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ pub use self::util::{
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
};
pub use self::util::{
supertraits, supertraits_with_repetitions, supertrait_def_ids, transitive_bounds, Supertraits,
SupertraitDefIds,
supertrait_def_ids, supertraits, supertraits_with_repetitions, transitive_bounds,
SupertraitDefIds, Supertraits,
};

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

tcx.arena.alloc_from_iter(supertraits_with_repetitions(tcx, trait_ref)
.map(move |trait_ref| {
let trait_methods = tcx
.associated_items(trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);

// Now, list each method's `DefId` and `InternalSubsts` (for within its trait).
// If the method can never be called from this object, produce `None`.
&*tcx.arena.alloc_from_iter(trait_methods.map(move |trait_method| {
debug!("vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;

// Some methods cannot be called on an object; skip those.
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
debug!("vtable_methods: not vtable safe");
return None;
}
tcx.arena.alloc_from_iter(supertraits_with_repetitions(tcx, trait_ref).map(move |trait_ref| {
let trait_methods = tcx
.associated_items(trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);

// Now, list each method's `DefId` and `InternalSubsts` (for within its trait).
// If the method can never be called from this object, produce `None`.
&*tcx.arena.alloc_from_iter(trait_methods.map(move |trait_method| {
debug!("vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;

// Some methods cannot be called on an object; skip those.
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
debug!("vtable_methods: not vtable safe");
return None;
}

// The method may have some early-bound lifetimes; add regions for those.
let substs = trait_ref.map_bound(|trait_ref| {
InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize]
}
})
});

// The trait type may have higher-ranked lifetimes in it;
// erase them if they appear, so that we get the type
// at some particular call site.
let substs =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);

// It's possible that the method relies on where-clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) {
debug!("vtable_methods: predicates do not hold");
return None;
}
// The method may have some early-bound lifetimes; add regions for those.
let substs = trait_ref.map_bound(|trait_ref| {
InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize]
}
})
});

// The trait type may have higher-ranked lifetimes in it;
// erase them if they appear, so that we get the type
// at some particular call site.
let substs =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);

// It's possible that the method relies on where-clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) {
debug!("vtable_methods: predicates do not hold");
return None;
}

Some((def_id, substs))
Some((def_id, substs))
}))
}))
}
Expand Down
56 changes: 28 additions & 28 deletions src/librustc_trait_selection/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1869,8 +1869,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
true
} else {
// Just allow upcast kinds 2 and 3 from above.
data_a.principal_def_id() == data_b.principal_def_id() &&
data_b.auto_traits()
data_a.principal_def_id() == data_b.principal_def_id()
&& data_b
.auto_traits()
// All of a's auto traits need to be in b's auto traits.
.all(|b| data_a.auto_traits().any(|a| a == b))
}
Expand Down Expand Up @@ -2696,27 +2697,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// where we can unify, because otherwise select would have
// reported an ambiguity. (When we do find a match, also
// record it for later.)
let nonmatching = util::supertraits_with_repetitions(tcx, poly_trait_ref)
.take_while(
|&trait_ref| match self.infcx.commit_if_ok(
|_| self.match_poly_trait_ref(obligation, trait_ref)
) {
let nonmatching =
util::supertraits_with_repetitions(tcx, poly_trait_ref).take_while(|&trait_ref| {
match self
.infcx
.commit_if_ok(|_| self.match_poly_trait_ref(obligation, trait_ref))
{
Ok(obligations) => {
upcast_trait_ref = Some(trait_ref);
nested.extend(obligations);
false
}
Err(_) => true,
},
);
}
});

// Additionally, for each of the non-matching predicates that
// we pass over, we sum up the set of number of vtable
// entries, so that we can compute the offset for the selected
// trait.
vtable_base = nonmatching
// Skip 3 entries in vtable per supertrait for `(drop, size, align)` metadata.
.map(|trait_ref| util::count_own_vtable_entries(tcx, trait_ref).checked_add(3).unwrap())
.map(|trait_ref| {
util::count_own_vtable_entries(tcx, trait_ref).checked_add(3).unwrap()
})
.sum();
}

Expand Down Expand Up @@ -2956,16 +2960,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let iter = data_a
.principal()
.map(ty::ExistentialPredicate::Trait)
.into_iter().chain(
.into_iter()
.chain(
data_a
.projection_bounds()
.map(|x| ty::ExistentialPredicate::Projection(x)),
)
.chain(
data_b
.auto_traits()
.map(ty::ExistentialPredicate::AutoTrait),
);
.chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
tcx.mk_existential_predicates(iter)
});
let source_with_target_auto_traits =
Expand Down Expand Up @@ -2995,24 +2996,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// (it doesn't matter which one we choose), but rather than resolve that in the
// general case (which is subtle), we can screen it out here easily enough.
nested.extend(
data_b.iter()
data_b
.iter()
// HACK(alexreg | nikomatsakis): we handle auto traits specially here
// because of cases like like `dyn Foo + Send + 'a` ->
// `dyn Foo + Send + 'b`, which requires proving the obligation
// `dyn Foo + Send: Send`. This is unfortunately ambiguous under the
// current trait solver model: it holds both because `Send` is a
// supertrait of `Foo + Send` and because there's an automatic impl of
// `Send` for the trait object.
.filter(|predicate| {
match predicate.skip_binder() {
ty::ExistentialPredicate::AutoTrait(did) =>
!data_a.auto_traits().any(|did_a| did_a == *did),
_ => true,
.filter(|predicate| match predicate.skip_binder() {
ty::ExistentialPredicate::AutoTrait(did) => {
!data_a.auto_traits().any(|did_a| did_a == *did)
}
_ => true,
})
.map(|predicate|
.map(|predicate| {
predicate_to_obligation(predicate.with_self_ty(tcx, source))
),
}),
);
} else {
// Require that the traits involved in this upcast are **equal**;
Expand All @@ -3031,7 +3032,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// because I want to continue rejecting that test (as we have
// done for quite some time) before we are firmly comfortable
// with what our behavior should be there. -nikomatsakis
let InferOk { obligations, .. } = self.infcx
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(target, source_with_target_auto_traits) // FIXME: see above.
.map_err(|_| Unimplemented)?;
Expand All @@ -3040,9 +3042,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

// Register an obligation for `'a: 'b`.
let outlives = ty::OutlivesPredicate(region_a, region_b);
nested.push(predicate_to_obligation(
ty::Binder::bind(outlives).to_predicate(),
));
nested.push(predicate_to_obligation(ty::Binder::bind(outlives).to_predicate()));
}

// `T` -> `Trait`
Expand Down
7 changes: 2 additions & 5 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,8 @@ pub trait AstConv<'tcx> {
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;

/// Returns the lifetime to use when a lifetime is omitted (and not elided).
fn re_infer(
&self,
param: Option<&ty::GenericParamDef>,
span: Span,
) -> Option<ty::Region<'tcx>>;
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
-> Option<ty::Region<'tcx>>;

/// Returns the type to use when a type is omitted.
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
Expand Down