Skip to content

Commit 871eb62

Browse files
committed
Stop allocating vtable entries for non-object-safe methods
1 parent 03c775c commit 871eb62

File tree

6 files changed

+54
-12
lines changed

6 files changed

+54
-12
lines changed

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,14 +647,14 @@ fn vtable_entries<'tcx>(
647647
.filter(|item| item.kind == ty::AssocKind::Fn);
648648
// Now list each method's DefId and InternalSubsts (for within its trait).
649649
// If the method can never be called from this object, produce `Vacant`.
650-
let own_entries = trait_methods.map(move |trait_method| {
650+
let own_entries = trait_methods.filter_map(move |trait_method| {
651651
debug!("vtable_entries: trait_method={:?}", trait_method);
652652
let def_id = trait_method.def_id;
653653

654654
// Some methods cannot be called on an object; skip those.
655655
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
656656
debug!("vtable_entries: not vtable safe");
657-
return VtblEntry::Vacant;
657+
return None;
658658
}
659659

660660
// The method may have some early-bound lifetimes; add regions for those.
@@ -681,7 +681,7 @@ fn vtable_entries<'tcx>(
681681
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
682682
if impossible_predicates(tcx, predicates.predicates) {
683683
debug!("vtable_entries: predicates do not hold");
684-
return VtblEntry::Vacant;
684+
return Some(VtblEntry::Vacant);
685685
}
686686

687687
let instance = ty::Instance::resolve_for_vtable(
@@ -691,7 +691,7 @@ fn vtable_entries<'tcx>(
691691
substs,
692692
)
693693
.expect("resolution failed during building vtable representation");
694-
VtblEntry::Method(instance)
694+
Some(VtblEntry::Method(instance))
695695
});
696696

697697
entries.extend(own_entries);

compiler/rustc_trait_selection/src/traits/util.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'
289289
// Count number of methods and add them to the total offset.
290290
// Skip over associated types and constants.
291291
for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
292-
if trait_item.kind == ty::AssocKind::Fn {
292+
let is_vtable_safe_method = trait_item.kind == ty::AssocKind::Fn
293+
&& super::is_vtable_safe_method(tcx, trait_ref.def_id(), trait_item);
294+
if is_vtable_safe_method {
293295
entries += 1;
294296
}
295297
}
@@ -308,13 +310,16 @@ pub fn get_vtable_index_of_object_method<N>(
308310
// add them to the total offset.
309311
// Skip over associated types and constants, as those aren't stored in the vtable.
310312
let mut entries = object.vtable_base;
311-
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
313+
let trait_def_id = object.upcast_trait_ref.def_id();
314+
for trait_item in tcx.associated_items(trait_def_id).in_definition_order() {
315+
let is_vtable_safe_method = trait_item.kind == ty::AssocKind::Fn
316+
&& super::is_vtable_safe_method(tcx, trait_def_id, trait_item);
312317
if trait_item.def_id == method_def_id {
313318
// The item with the ID we were given really ought to be a method.
314-
assert_eq!(trait_item.kind, ty::AssocKind::Fn);
319+
assert!(is_vtable_safe_method);
315320
return entries;
316321
}
317-
if trait_item.kind == ty::AssocKind::Fn {
322+
if is_vtable_safe_method {
318323
entries += 1;
319324
}
320325
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// build-fail
2+
#![feature(rustc_attrs)]
3+
4+
// Ensure that non-object-safe methods in Iterator does not generate
5+
// vtable entries.
6+
7+
#[rustc_dump_vtable]
8+
trait A: Iterator {}
9+
//~^ error Vtable
10+
11+
impl<T> A for T where T: Iterator {}
12+
13+
fn foo(_a: &mut dyn A<Item=u8>) {
14+
}
15+
16+
fn main() {
17+
foo(&mut vec![0, 1, 2, 3].into_iter());
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: Vtable entries for `<std::vec::IntoIter<u8> as A>`: [
2+
MetadataDropInPlace,
3+
MetadataSize,
4+
MetadataAlign,
5+
Method(<std::vec::IntoIter<u8> as Iterator>::next),
6+
Method(<std::vec::IntoIter<u8> as Iterator>::size_hint),
7+
Method(<std::vec::IntoIter<u8> as Iterator>::advance_by),
8+
Method(<std::vec::IntoIter<u8> as Iterator>::nth),
9+
]
10+
--> $DIR/vtable-non-object-safe.rs:8:1
11+
|
12+
LL | trait A: Iterator {}
13+
| ^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to previous error
16+

src/test/ui/traits/vtable/vtable-vacant.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
// build-fail
22
#![feature(rustc_attrs)]
3+
#![feature(negative_impls)]
4+
#![allow(where_clauses_object_safety)]
35

46
// B --> A
57

68
#[rustc_dump_vtable]
79
trait A {
810
fn foo_a1(&self) {}
9-
fn foo_a2(&self) where Self: Sized {}
11+
fn foo_a2(&self) where Self: Send {}
1012
}
1113

1214
#[rustc_dump_vtable]
1315
trait B: A {
1416
//~^ error Vtable
1517
fn foo_b1(&self) {}
16-
fn foo_b2() where Self: Sized {}
18+
fn foo_b2(&self) where Self: Send {}
1719
}
1820

1921
struct S;
22+
impl !Send for S {}
2023

2124
impl A for S {}
2225
impl B for S {}

src/test/ui/traits/vtable/vtable-vacant.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ error: Vtable entries for `<S as B>`: [
77
Method(<S as B>::foo_b1),
88
Vacant,
99
]
10-
--> $DIR/vtable-vacant.rs:13:1
10+
--> $DIR/vtable-vacant.rs:15:1
1111
|
1212
LL | / trait B: A {
1313
LL | |
1414
LL | | fn foo_b1(&self) {}
15-
LL | | fn foo_b2() where Self: Sized {}
15+
LL | | fn foo_b2(&self) where Self: Send {}
1616
LL | | }
1717
| |_^
1818

0 commit comments

Comments
 (0)