Skip to content

Commit d40408e

Browse files
committed
Verify that type implements trait in vtable_for. Return None if not.
1 parent 17b5402 commit d40408e

File tree

2 files changed

+48
-22
lines changed

2 files changed

+48
-22
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@
44
55
use std::assert_matches::assert_matches;
66

7-
use rustc_abi::{FieldIdx, HasDataLayout, Size};
7+
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size};
88
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
9+
use rustc_infer::infer::TyCtxtInferExt;
910
use rustc_middle::mir::interpret::{read_target_uint, write_target_uint};
1011
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
1112
use rustc_middle::ty::layout::TyAndLayout;
12-
use rustc_middle::ty::{Ty, TyCtxt};
13+
use rustc_middle::ty::{Ty, TyCtxt, Upcast};
1314
use rustc_middle::{bug, ty};
1415
use rustc_span::{Symbol, sym};
16+
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
1517
use tracing::trace;
1618

1719
use super::memory::MemoryKind;
1820
use super::util::ensure_monomorphic_enough;
1921
use super::{
2022
Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy,
2123
PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format,
22-
interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
24+
interp_ok, throw_inval, throw_ub_custom, throw_ub_format, throw_unsup_format,
2325
};
2426
use crate::fluent_generated as fluent;
2527

@@ -151,18 +153,41 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
151153
sym::vtable_for => {
152154
let tp_ty = instance.args.type_at(0);
153155
let result_ty = instance.args.type_at(1);
154-
//let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span);
155156

156157
ensure_monomorphic_enough(tcx, tp_ty)?;
157158
ensure_monomorphic_enough(tcx, result_ty)?;
158159

159-
// Get vtable
160-
//let vtable_ptr = self.get_vtable_ptr(tp_ty, result_ty.into())?;
160+
let ty::Dynamic(preds, _, ty::Dyn) = result_ty.kind() else {
161+
throw_unsup_format!(
162+
"Invalid type provided to vtable_for::<T, U>. U must be dyn Trait, got {result_ty}."
163+
);
164+
};
161165

162-
//let dyn_metadata = metadata(vtable_ptr);
163-
//let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128());
164-
//let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
165-
//self.copy_op(&val, dest)?;
166+
let (infcx, param_env) = self
167+
.tcx
168+
.infer_ctxt()
169+
.build_with_typing_env(ty::TypingEnv::fully_monomorphized());
170+
171+
let type_impls_trait = preds.iter().all(|pred| {
172+
let trait_ref = ty::TraitRef::new(tcx, pred.def_id(), [tp_ty]);
173+
let pred: ty::Predicate<'tcx> = trait_ref.upcast(tcx);
174+
175+
let ocx = ObligationCtxt::new(&infcx);
176+
ocx.register_obligation(Obligation::new(
177+
tcx,
178+
ObligationCause::dummy(),
179+
param_env,
180+
pred,
181+
));
182+
ocx.select_all_or_error().is_empty()
183+
});
184+
185+
if type_impls_trait {
186+
let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?;
187+
self.write_pointer(vtable_ptr, dest)?;
188+
} else {
189+
self.write_discriminant(FIRST_VARIANT, dest)?;
190+
}
166191
}
167192
sym::variant_count => {
168193
let tp_ty = instance.args.type_at(0);

library/coretests/tests/intrinsics.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use core::any::TypeId;
2-
use core::intrinsics::assume;
2+
use core::intrinsics::{assume, vtable_for};
3+
use std::fmt::Debug;
4+
use std::option::Option;
5+
use std::ptr::DynMetadata;
36

47
#[test]
58
fn test_typeid_sized_types() {
@@ -195,18 +198,16 @@ fn carrying_mul_add_fallback_i128() {
195198
}
196199

197200
#[test]
201+
#[allow(dead_code)]
198202
fn test_vtable_for() {
199-
use std::fmt::Debug;
200-
use std::intrinsics::vtable_for;
201-
use std::option::Option;
202-
use std::ptr::DynMetadata;
203-
204-
#[allow(dead_code)]
205203
#[derive(Debug)]
206-
struct A {
207-
index: usize,
208-
}
209-
const debug_vtable: Option<DynMetadata<dyn Debug>> = vtable_for::<A, dyn Debug>();
204+
struct A {}
205+
206+
struct B {}
207+
208+
const A_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<A, dyn Debug>();
209+
assert!(A_VTABLE.is_some());
210210

211-
println!("{debug_vtable:?}");
211+
const B_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<B, dyn Debug>();
212+
assert!(B_VTABLE.is_none());
212213
}

0 commit comments

Comments
 (0)