Skip to content

Commit 2eda95b

Browse files
committed
mentioned items: also handle vtables
1 parent 6774cb4 commit 2eda95b

File tree

6 files changed

+107
-45
lines changed

6 files changed

+107
-45
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,11 @@ impl<'tcx> CoroutineInfo<'tcx> {
319319
pub enum MentionedItem<'tcx> {
320320
Fn(DefId, GenericArgsRef<'tcx>),
321321
Drop(Ty<'tcx>),
322-
// FIXME: add Vtable { source_ty: Ty<'tcx>, target_ty: Ty<'tcx> },
322+
/// Unsizing casts might require vtables, so we have to record them.
323+
UnsizeCast {
324+
source_ty: Ty<'tcx>,
325+
target_ty: Ty<'tcx>,
326+
},
323327
// FIXME: do we have to add closures?
324328
}
325329

compiler/rustc_mir_transform/src/mentioned_items.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_middle::mir::visit::Visitor;
22
use rustc_middle::mir::{self, ConstOperand, Location, MentionedItem, MirPass};
3-
use rustc_middle::ty::{self, TyCtxt};
3+
use rustc_middle::ty::{self, adjustment::PointerCoercion, TyCtxt};
44
use rustc_session::Session;
55
use rustc_span::source_map::Spanned;
66

@@ -54,4 +54,28 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
5454
_ => {}
5555
}
5656
}
57+
58+
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
59+
self.super_rvalue(rvalue, location);
60+
match *rvalue {
61+
// We need to detect unsizing casts that required vtables.
62+
mir::Rvalue::Cast(
63+
mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
64+
ref operand,
65+
target_ty,
66+
)
67+
| mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
68+
let span = self.body.source_info(location).span;
69+
self.mentioned_items.push(Spanned {
70+
node: MentionedItem::UnsizeCast {
71+
source_ty: operand.ty(self.body, self.tcx),
72+
target_ty,
73+
},
74+
span,
75+
});
76+
}
77+
// Function pointer casts are already handled by `visit_constant` above.
78+
_ => {}
79+
}
80+
}
5781
}

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
735735
where
736736
T: TypeFoldable<TyCtxt<'tcx>>,
737737
{
738-
debug!("monomorphize: self.instance={:?}", self.instance);
738+
trace!("monomorphize: self.instance={:?}", self.instance);
739739
self.instance.instantiate_mir_and_normalize_erasing_regions(
740740
self.tcx,
741741
ty::ParamEnv::reveal_all(),
@@ -1339,35 +1339,37 @@ fn create_mono_items_for_vtable_methods<'tcx>(
13391339
) {
13401340
assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars());
13411341

1342-
if let ty::Dynamic(trait_ty, ..) = trait_ty.kind() {
1343-
if let Some(principal) = trait_ty.principal() {
1344-
let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
1345-
assert!(!poly_trait_ref.has_escaping_bound_vars());
1346-
1347-
// Walk all methods of the trait, including those of its supertraits
1348-
let entries = tcx.vtable_entries(poly_trait_ref);
1349-
let methods = entries
1350-
.iter()
1351-
.filter_map(|entry| match entry {
1352-
VtblEntry::MetadataDropInPlace
1353-
| VtblEntry::MetadataSize
1354-
| VtblEntry::MetadataAlign
1355-
| VtblEntry::Vacant => None,
1356-
VtblEntry::TraitVPtr(_) => {
1357-
// all super trait items already covered, so skip them.
1358-
None
1359-
}
1360-
VtblEntry::Method(instance) => {
1361-
Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
1362-
}
1363-
})
1364-
.map(|item| create_fn_mono_item(tcx, item, source));
1365-
output.extend(methods);
1366-
}
1367-
1368-
// Also add the destructor.
1369-
visit_drop_use(tcx, impl_ty, false, source, output);
1342+
let ty::Dynamic(trait_ty, ..) = trait_ty.kind() else {
1343+
bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type");
1344+
};
1345+
if let Some(principal) = trait_ty.principal() {
1346+
let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
1347+
assert!(!poly_trait_ref.has_escaping_bound_vars());
1348+
1349+
// Walk all methods of the trait, including those of its supertraits
1350+
let entries = tcx.vtable_entries(poly_trait_ref);
1351+
debug!(?entries);
1352+
let methods = entries
1353+
.iter()
1354+
.filter_map(|entry| match entry {
1355+
VtblEntry::MetadataDropInPlace
1356+
| VtblEntry::MetadataSize
1357+
| VtblEntry::MetadataAlign
1358+
| VtblEntry::Vacant => None,
1359+
VtblEntry::TraitVPtr(_) => {
1360+
// all super trait items already covered, so skip them.
1361+
None
1362+
}
1363+
VtblEntry::Method(instance) => {
1364+
Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
1365+
}
1366+
})
1367+
.map(|item| create_fn_mono_item(tcx, item, source));
1368+
output.extend(methods);
13701369
}
1370+
1371+
// Also add the destructor.
1372+
visit_drop_use(tcx, impl_ty, false, source, output);
13711373
}
13721374

13731375
//=-----------------------------------------------------------------------------
@@ -1686,7 +1688,8 @@ fn collect_items_of_instance<'tcx>(
16861688
}
16871689
}
16881690

1689-
/// `item` must be already monomorphized
1691+
/// `item` must be already monomorphized.
1692+
#[instrument(skip(tcx, span, output), level = "debug")]
16901693
fn visit_mentioned_item<'tcx>(
16911694
tcx: TyCtxt<'tcx>,
16921695
item: &MentionedItem<'tcx>,
@@ -1705,6 +1708,18 @@ fn visit_mentioned_item<'tcx>(
17051708
MentionedItem::Drop(ty) => {
17061709
visit_drop_use(tcx, ty, /*is_direct_call*/ true, span, output);
17071710
}
1711+
MentionedItem::UnsizeCast { source_ty, target_ty } => {
1712+
let (source_ty, target_ty) =
1713+
find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
1714+
// This could also be a different Unsize instruction, like
1715+
// from a fixed sized array to a slice. But we are only
1716+
// interested in things that produce a vtable.
1717+
if (target_ty.is_trait() && !source_ty.is_trait())
1718+
|| (target_ty.is_dyn_star() && !source_ty.is_dyn_star())
1719+
{
1720+
create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output);
1721+
}
1722+
}
17081723
}
17091724
}
17101725

tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error[E0080]: evaluation of `Fail::<i32>::C` failed
2-
--> $DIR/collect-in-dead-vtable.rs:11:19
2+
--> $DIR/collect-in-dead-vtable.rs:8:19
33
|
44
LL | const C: () = panic!();
5-
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:11:19
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:8:19
66
|
77
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
88

99
note: erroneous constant encountered
10-
--> $DIR/collect-in-dead-vtable.rs:25:21
10+
--> $DIR/collect-in-dead-vtable.rs:21:21
1111
|
1212
LL | let _ = Fail::<T>::C;
1313
| ^^^^^^^^^^^^
1414

1515
note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
16-
--> $DIR/collect-in-dead-vtable.rs:34:40
16+
--> $DIR/collect-in-dead-vtable.rs:30:40
1717
|
18-
LL | let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
18+
LL | let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
1919
| ^^
2020

2121
error: aborting due to 1 previous error
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-vtable.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:8:19
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-vtable.rs:21:21
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
16+
--> $DIR/collect-in-dead-vtable.rs:30:40
17+
|
18+
LL | let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
19+
| ^^
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0080`.

tests/ui/consts/required-consts/collect-in-dead-vtable.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
//@revisions: noopt opt
2-
//@[noopt] build-fail
2+
//@ build-fail
33
//@[opt] compile-flags: -O
4-
//FIXME: `opt` revision currently does not stop with an error due to
5-
//<https://github.com/rust-lang/rust/issues/107503>.
6-
//@[opt] build-pass
74
//! This fails without optimizations, so it should also fail with optimizations.
85
96
struct Fail<T>(T);
107
impl<T> Fail<T> {
11-
const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
8+
const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
129
}
1310

1411
trait MyTrait {
@@ -17,8 +14,7 @@ trait MyTrait {
1714

1815
// This function is not actually called, but it is mentioned in a vtable in a function that is
1916
// called. Make sure we still find this error.
20-
// This relies on mono-item collection checking `required_consts` in functions that are referenced
21-
// in vtables that syntactically appear in collected functions (even inside dead code).
17+
// This ensures that we are properly considering vtables when gathering "mentioned" items.
2218
impl<T> MyTrait for Vec<T> {
2319
fn not_called(&self) {
2420
if false {
@@ -31,7 +27,7 @@ impl<T> MyTrait for Vec<T> {
3127
fn called<T>() {
3228
if false {
3329
let v: Vec<T> = Vec::new();
34-
let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
30+
let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
3531
}
3632
}
3733

0 commit comments

Comments
 (0)