Skip to content

Commit

Permalink
Rollup merge of rust-lang#131864 - lrh2000:upcast_reorder, r=WaffleLa…
Browse files Browse the repository at this point in the history
…pkin

Never emit `vptr` for empty/auto traits

Emiting `vptr`s for empty/auto traits is unnecessary (rust-lang#114942) and causes unsoundness in `trait_upcasting` (rust-lang#131813). This PR should ensure that we never emit vtables for such traits. See the linked issues for more details.

I'm not sure if I can add tests for the vtable layout. So this PR only adds tests for the soundness hole (i.e., the segmentation fault will disappear after this PR).

Fixes rust-lang#114942
Fixes rust-lang#131813

Cc rust-lang#65991 (tracking issue for `trait_upcasting`)

r? `@WaffleLapkin`  (per rust-lang#131813 (comment))
  • Loading branch information
jieyouxu authored Oct 18, 2024
2 parents 39af44d + 781bff0 commit 765e8c7
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 14 deletions.
11 changes: 5 additions & 6 deletions compiler/rustc_trait_selection/src/traits/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,17 @@ fn prepare_vtable_segments_inner<'tcx, T>(

// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
let has_entries =
has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id());

segment_visitor(VtblSegment::TraitOwnEntries {
trait_ref: inner_most_trait_ref,
emit_vptr: emit_vptr && !tcx.sess.opts.unstable_opts.no_trait_vptr,
emit_vptr: emit_vptr && has_entries && !tcx.sess.opts.unstable_opts.no_trait_vptr,
})?;

// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,
// we'll need to emit vptrs from now on.
if !emit_vptr_on_new_entry
&& has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id())
{
emit_vptr_on_new_entry = true;
}
emit_vptr_on_new_entry |= has_entries;

if let Some(next_inner_most_trait_ref) =
siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/traits/object/print_vtable_sizes.stdout
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "E", "entries": "6", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "2", "upcasting_cost_percent": "50" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "G", "entries": "14", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "3", "upcasting_cost_percent": "27.27272727272727" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "G", "entries": "13", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "2", "upcasting_cost_percent": "18.181818181818183" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "E", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
Expand Down
29 changes: 29 additions & 0 deletions tests/ui/traits/upcast_reorder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ run-pass
//
// issue: <https://github.com/rust-lang/rust/issues/131813>

#![feature(trait_upcasting)]

trait Pollable {
#[allow(unused)]
fn poll(&self) {}
}
trait FileIo: Pollable + Send + Sync {
fn read(&self) {}
}
trait Terminal: Send + Sync + FileIo {}

struct A;

impl Pollable for A {}
impl FileIo for A {}
impl Terminal for A {}

fn main() {
let a = A;

let b = &a as &dyn Terminal;
let c = b as &dyn FileIo;

c.read();
}
6 changes: 0 additions & 6 deletions tests/ui/traits/vtable/multiple-markers.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ error: vtable entries for `<S as B>`: [
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
TraitVPtr(<S as M2>),
]
--> $DIR/multiple-markers.rs:24:1
|
Expand All @@ -26,8 +25,6 @@ error: vtable entries for `<S as C>`: [
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
TraitVPtr(<S as M1>),
TraitVPtr(<S as M2>),
]
--> $DIR/multiple-markers.rs:27:1
|
Expand All @@ -39,9 +36,6 @@ error: vtable entries for `<S as D>`: [
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
TraitVPtr(<S as M0>),
TraitVPtr(<S as M1>),
TraitVPtr(<S as M2>),
]
--> $DIR/multiple-markers.rs:30:1
|
Expand Down

0 comments on commit 765e8c7

Please sign in to comment.