diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4f6e2cc005160..1d98b5be8741c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -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, + ); } } @@ -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) { @@ -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)); @@ -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); } }); } @@ -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 { .. } => {} } @@ -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); } } @@ -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) + } _ => {} } } @@ -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 } => { diff --git a/tests/ui/coercion/vtable-size-overflow-in-const-coercion-141911.rs b/tests/ui/coercion/vtable-size-overflow-in-const-coercion-141911.rs new file mode 100644 index 0000000000000..423b8b007fc79 --- /dev/null +++ b/tests/ui/coercion/vtable-size-overflow-in-const-coercion-141911.rs @@ -0,0 +1,16 @@ +//@ run-pass + +trait MyTrait { + fn virtualize(&self); +} +struct VirtualWrapper(T, T); + +impl MyTrait for T { + fn virtualize(&self) { + const { std::ptr::null::>() as *const dyn MyTrait }; + } +} + +fn main() { + 0u8.virtualize(); +}