Stop allocating vtable entries for non-object-safe methods
This commit is contained in:
parent
03c775c955
commit
871eb6233e
@ -647,14 +647,14 @@ fn vtable_entries<'tcx>(
|
|||||||
.filter(|item| item.kind == ty::AssocKind::Fn);
|
.filter(|item| item.kind == ty::AssocKind::Fn);
|
||||||
// Now list each method's DefId and InternalSubsts (for within its trait).
|
// Now list each method's DefId and InternalSubsts (for within its trait).
|
||||||
// If the method can never be called from this object, produce `Vacant`.
|
// If the method can never be called from this object, produce `Vacant`.
|
||||||
let own_entries = trait_methods.map(move |trait_method| {
|
let own_entries = trait_methods.filter_map(move |trait_method| {
|
||||||
debug!("vtable_entries: trait_method={:?}", trait_method);
|
debug!("vtable_entries: trait_method={:?}", trait_method);
|
||||||
let def_id = trait_method.def_id;
|
let def_id = trait_method.def_id;
|
||||||
|
|
||||||
// Some methods cannot be called on an object; skip those.
|
// Some methods cannot be called on an object; skip those.
|
||||||
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
|
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
|
||||||
debug!("vtable_entries: not vtable safe");
|
debug!("vtable_entries: not vtable safe");
|
||||||
return VtblEntry::Vacant;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The method may have some early-bound lifetimes; add regions for those.
|
// The method may have some early-bound lifetimes; add regions for those.
|
||||||
@ -681,7 +681,7 @@ fn vtable_entries<'tcx>(
|
|||||||
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
|
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
|
||||||
if impossible_predicates(tcx, predicates.predicates) {
|
if impossible_predicates(tcx, predicates.predicates) {
|
||||||
debug!("vtable_entries: predicates do not hold");
|
debug!("vtable_entries: predicates do not hold");
|
||||||
return VtblEntry::Vacant;
|
return Some(VtblEntry::Vacant);
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = ty::Instance::resolve_for_vtable(
|
let instance = ty::Instance::resolve_for_vtable(
|
||||||
@ -691,7 +691,7 @@ fn vtable_entries<'tcx>(
|
|||||||
substs,
|
substs,
|
||||||
)
|
)
|
||||||
.expect("resolution failed during building vtable representation");
|
.expect("resolution failed during building vtable representation");
|
||||||
VtblEntry::Method(instance)
|
Some(VtblEntry::Method(instance))
|
||||||
});
|
});
|
||||||
|
|
||||||
entries.extend(own_entries);
|
entries.extend(own_entries);
|
||||||
|
@ -289,7 +289,9 @@ pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'
|
|||||||
// Count number of methods and add them to the total offset.
|
// Count number of methods and add them to the total offset.
|
||||||
// Skip over associated types and constants.
|
// Skip over associated types and constants.
|
||||||
for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
|
for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
|
||||||
if trait_item.kind == ty::AssocKind::Fn {
|
let is_vtable_safe_method = trait_item.kind == ty::AssocKind::Fn
|
||||||
|
&& super::is_vtable_safe_method(tcx, trait_ref.def_id(), trait_item);
|
||||||
|
if is_vtable_safe_method {
|
||||||
entries += 1;
|
entries += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,13 +310,16 @@ pub fn get_vtable_index_of_object_method<N>(
|
|||||||
// add them to the total offset.
|
// add them to the total offset.
|
||||||
// Skip over associated types and constants, as those aren't stored in the vtable.
|
// Skip over associated types and constants, as those aren't stored in the vtable.
|
||||||
let mut entries = object.vtable_base;
|
let mut entries = object.vtable_base;
|
||||||
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
|
let trait_def_id = object.upcast_trait_ref.def_id();
|
||||||
|
for trait_item in tcx.associated_items(trait_def_id).in_definition_order() {
|
||||||
|
let is_vtable_safe_method = trait_item.kind == ty::AssocKind::Fn
|
||||||
|
&& super::is_vtable_safe_method(tcx, trait_def_id, trait_item);
|
||||||
if trait_item.def_id == method_def_id {
|
if trait_item.def_id == method_def_id {
|
||||||
// The item with the ID we were given really ought to be a method.
|
// The item with the ID we were given really ought to be a method.
|
||||||
assert_eq!(trait_item.kind, ty::AssocKind::Fn);
|
assert!(is_vtable_safe_method);
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
if trait_item.kind == ty::AssocKind::Fn {
|
if is_vtable_safe_method {
|
||||||
entries += 1;
|
entries += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
src/test/ui/traits/vtable/vtable-non-object-safe.rs
Normal file
18
src/test/ui/traits/vtable/vtable-non-object-safe.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// build-fail
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
// Ensure that non-object-safe methods in Iterator does not generate
|
||||||
|
// vtable entries.
|
||||||
|
|
||||||
|
#[rustc_dump_vtable]
|
||||||
|
trait A: Iterator {}
|
||||||
|
//~^ error Vtable
|
||||||
|
|
||||||
|
impl<T> A for T where T: Iterator {}
|
||||||
|
|
||||||
|
fn foo(_a: &mut dyn A<Item=u8>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo(&mut vec![0, 1, 2, 3].into_iter());
|
||||||
|
}
|
16
src/test/ui/traits/vtable/vtable-non-object-safe.stderr
Normal file
16
src/test/ui/traits/vtable/vtable-non-object-safe.stderr
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
error: Vtable entries for `<std::vec::IntoIter<u8> as A>`: [
|
||||||
|
MetadataDropInPlace,
|
||||||
|
MetadataSize,
|
||||||
|
MetadataAlign,
|
||||||
|
Method(<std::vec::IntoIter<u8> as Iterator>::next),
|
||||||
|
Method(<std::vec::IntoIter<u8> as Iterator>::size_hint),
|
||||||
|
Method(<std::vec::IntoIter<u8> as Iterator>::advance_by),
|
||||||
|
Method(<std::vec::IntoIter<u8> as Iterator>::nth),
|
||||||
|
]
|
||||||
|
--> $DIR/vtable-non-object-safe.rs:8:1
|
||||||
|
|
|
||||||
|
LL | trait A: Iterator {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
@ -1,22 +1,25 @@
|
|||||||
// build-fail
|
// build-fail
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![allow(where_clauses_object_safety)]
|
||||||
|
|
||||||
// B --> A
|
// B --> A
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait A {
|
trait A {
|
||||||
fn foo_a1(&self) {}
|
fn foo_a1(&self) {}
|
||||||
fn foo_a2(&self) where Self: Sized {}
|
fn foo_a2(&self) where Self: Send {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait B: A {
|
trait B: A {
|
||||||
//~^ error Vtable
|
//~^ error Vtable
|
||||||
fn foo_b1(&self) {}
|
fn foo_b1(&self) {}
|
||||||
fn foo_b2() where Self: Sized {}
|
fn foo_b2(&self) where Self: Send {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
impl !Send for S {}
|
||||||
|
|
||||||
impl A for S {}
|
impl A for S {}
|
||||||
impl B for S {}
|
impl B for S {}
|
||||||
|
@ -7,12 +7,12 @@ error: Vtable entries for `<S as B>`: [
|
|||||||
Method(<S as B>::foo_b1),
|
Method(<S as B>::foo_b1),
|
||||||
Vacant,
|
Vacant,
|
||||||
]
|
]
|
||||||
--> $DIR/vtable-vacant.rs:13:1
|
--> $DIR/vtable-vacant.rs:15:1
|
||||||
|
|
|
|
||||||
LL | / trait B: A {
|
LL | / trait B: A {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | fn foo_b1(&self) {}
|
LL | | fn foo_b1(&self) {}
|
||||||
LL | | fn foo_b2() where Self: Sized {}
|
LL | | fn foo_b2(&self) where Self: Send {}
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user