@@ -153,16 +153,26 @@ fn prepare_vtable_segments_inner<'tcx, T>(
153
153
154
154
// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
155
155
while let Some ( ( inner_most_trait_ref, emit_vptr, mut siblings) ) = stack. pop ( ) {
156
- let has_entries = has_own_existential_vtable_entries ( tcx, inner_most_trait_ref. def_id ) ;
157
-
156
+ let is_non_auto = !tcx. trait_is_auto ( inner_most_trait_ref. def_id ) ;
157
+
158
+ // We don't need to emit a vptr for "truly-empty" supertraits, but we *do* need to emit a
159
+ // vptr for supertraits that have no methods, but that themselves have supertraits
160
+ // with methods (so we can't just use `own_existential_vtable_entries`, as that
161
+ // does not account for vtable entries coming from supertraits).
162
+ // As an overapproximation, we treat all non-auto traits as though they are not empty.
163
+ // FIXME: don't emit vptr for empty supertraits (whose vtables would only have DSA),
164
+ // (even if they aren't auto traits), but in a way that doesn't
165
+ // regress #131813 or #145752. Note that this would require considering their
166
+ // supertraits, not just their own entries.
158
167
segment_visitor ( VtblSegment :: TraitOwnEntries {
159
168
trait_ref : inner_most_trait_ref,
160
- emit_vptr : emit_vptr && has_entries && !tcx. sess . opts . unstable_opts . no_trait_vptr ,
169
+ emit_vptr : emit_vptr && is_non_auto && !tcx. sess . opts . unstable_opts . no_trait_vptr ,
161
170
} ) ?;
162
171
163
172
// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,
164
173
// we'll need to emit vptrs from now on.
165
- emit_vptr_on_new_entry |= has_entries;
174
+ // FIXME: as above, we overapproximate and assume any non-auto trait could have methods.
175
+ emit_vptr_on_new_entry |= is_non_auto;
166
176
167
177
if let Some ( next_inner_most_trait_ref) =
168
178
siblings. find ( |& sibling| visited. insert ( sibling. upcast ( tcx) ) )
@@ -185,10 +195,6 @@ fn maybe_iter<I: Iterator>(i: Option<I>) -> impl Iterator<Item = I::Item> {
185
195
i. into_iter ( ) . flatten ( )
186
196
}
187
197
188
- fn has_own_existential_vtable_entries ( tcx : TyCtxt < ' _ > , trait_def_id : DefId ) -> bool {
189
- own_existential_vtable_entries_iter ( tcx, trait_def_id) . next ( ) . is_some ( )
190
- }
191
-
192
198
fn own_existential_vtable_entries ( tcx : TyCtxt < ' _ > , trait_def_id : DefId ) -> & [ DefId ] {
193
199
tcx. arena . alloc_from_iter ( own_existential_vtable_entries_iter ( tcx, trait_def_id) )
194
200
}
0 commit comments