Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,12 @@ fn collect_items_rec<'tcx>(

if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
for &prov in alloc.inner().provenance().ptrs().values() {
collect_alloc(tcx, prov.alloc_id(), &mut used_items);
collect_alloc(
tcx,
prov.alloc_id(),
CollectionMode::UsedItems,
&mut used_items,
);
}
}

Expand Down Expand Up @@ -815,7 +820,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, _location: Location) {
// No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`.
let Some(val) = self.eval_constant(constant) else { return };
collect_const_value(self.tcx, val, self.used_items);
collect_const_value(self.tcx, val, CollectionMode::UsedItems, self.used_items);
}

fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
Expand Down Expand Up @@ -1262,7 +1267,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
}

/// Scans the CTFE alloc in order to find function pointers and statics that must be monomorphized.
fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) {
fn collect_alloc<'tcx>(
tcx: TyCtxt<'tcx>,
alloc_id: AllocId,
mode: CollectionMode,
output: &mut MonoItems<'tcx>,
) {
match tcx.global_alloc(alloc_id) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
Expand All @@ -1279,7 +1289,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
if !ptrs.is_empty() {
rustc_data_structures::stack::ensure_sufficient_stack(move || {
for &prov in ptrs.values() {
collect_alloc(tcx, prov.alloc_id(), output);
collect_alloc(tcx, prov.alloc_id(), mode, output);
}
});
}
Expand All @@ -1291,13 +1301,19 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
}
}
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc_id = tcx.vtable_allocation((
ty,
dyn_ty
.principal()
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
));
collect_alloc(tcx, alloc_id, output)
// In "mentioned items" mode, skip walking vtable allocations to avoid infinite
// recursion when a vtable method's body contains a const that embeds another
// vtable (see #141911). Vtable methods are only needed for codegen, not for
// error checking. In "used items" mode, we must collect them.
if mode == CollectionMode::UsedItems {
let alloc_id = tcx.vtable_allocation((
ty,
dyn_ty
.principal()
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
));
collect_alloc(tcx, alloc_id, mode, output)
}
}
GlobalAlloc::TypeId { .. } => {}
}
Expand Down Expand Up @@ -1356,7 +1372,7 @@ fn collect_items_of_instance<'tcx>(
// them errors.
for const_op in body.required_consts() {
if let Some(val) = collector.eval_constant(const_op) {
collect_const_value(tcx, val, &mut mentioned_items);
collect_const_value(tcx, val, mode, &mut mentioned_items);
}
}

Expand Down Expand Up @@ -1443,14 +1459,17 @@ fn visit_mentioned_item<'tcx>(
fn collect_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
value: mir::ConstValue,
mode: CollectionMode,
output: &mut MonoItems<'tcx>,
) {
match value {
mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
collect_alloc(tcx, ptr.provenance.alloc_id(), output)
collect_alloc(tcx, ptr.provenance.alloc_id(), mode, output)
}
mir::ConstValue::Indirect { alloc_id, .. }
| mir::ConstValue::Slice { alloc_id, meta: _ } => collect_alloc(tcx, alloc_id, output),
| mir::ConstValue::Slice { alloc_id, meta: _ } => {
collect_alloc(tcx, alloc_id, mode, output)
}
_ => {}
}
}
Expand Down Expand Up @@ -1581,7 +1600,7 @@ impl<'v> RootCollector<'_, 'v> {
let Ok(val) = self.tcx.const_eval_poly(def_id) else {
return;
};
collect_const_value(self.tcx, val, self.output);
collect_const_value(self.tcx, val, CollectionMode::UsedItems, self.output);
}
}
DefKind::Impl { of_trait: true } => {
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/coercion/vtable-size-overflow-in-const-coercion-141911.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ run-pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem resurfaces when compiling without optimizations -Zmir-opt-level=0. The motivation behind "mentioned" collection mode is to ensure consistency across optimization levels. In that sense the existing implementation is working as intended (putting aside the glaring issue of ICE itself).


trait MyTrait {
fn virtualize(&self);
}
struct VirtualWrapper<T>(T, T);

impl<T: 'static> MyTrait for T {
fn virtualize(&self) {
const { std::ptr::null::<VirtualWrapper<T>>() as *const dyn MyTrait };
}
}

fn main() {
0u8.virtualize();
}
Loading