|
| 1 | +use rustc_infer::infer::TyCtxtInferExt; |
| 2 | +use rustc_infer::traits::ObligationCause; |
1 | 3 | use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
2 | 4 | use rustc_middle::ty::layout::LayoutOf;
|
3 | 5 | use rustc_middle::ty::{self, Ty};
|
4 | 6 | use rustc_target::abi::{Align, Size};
|
| 7 | +use rustc_trait_selection::traits::ObligationCtxt; |
5 | 8 | use tracing::trace;
|
6 | 9 |
|
7 | 10 | use super::util::ensure_monomorphic_enough;
|
8 |
| -use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable}; |
| 11 | +use super::{throw_ub, InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable}; |
9 | 12 |
|
10 | 13 | impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
11 | 14 | /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
|
@@ -44,6 +47,37 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
44 | 47 | Ok((layout.size, layout.align.abi))
|
45 | 48 | }
|
46 | 49 |
|
| 50 | + /// Check that the given vtable trait is valid for a pointer/reference/place with the given |
| 51 | + /// expected trait type. |
| 52 | + pub(super) fn check_vtable_for_type( |
| 53 | + &self, |
| 54 | + vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>, |
| 55 | + expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, |
| 56 | + ) -> InterpResult<'tcx> { |
| 57 | + // Fast path: if they are equal, it's all fine. |
| 58 | + if expected_trait.principal() == vtable_trait { |
| 59 | + return Ok(()); |
| 60 | + } |
| 61 | + if let (Some(expected_trait), Some(vtable_trait)) = |
| 62 | + (expected_trait.principal(), vtable_trait) |
| 63 | + { |
| 64 | + // Slow path: spin up an inference context to check if these traits are sufficiently equal. |
| 65 | + let infcx = self.tcx.infer_ctxt().build(); |
| 66 | + let ocx = ObligationCtxt::new(&infcx); |
| 67 | + let cause = ObligationCause::dummy_with_span(self.cur_span()); |
| 68 | + // equate the two trait refs after normalization |
| 69 | + let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait); |
| 70 | + let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait); |
| 71 | + if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() { |
| 72 | + if ocx.select_all_or_error().is_empty() { |
| 73 | + // All good. |
| 74 | + return Ok(()); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); |
| 79 | + } |
| 80 | + |
47 | 81 | /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
|
48 | 82 | pub(super) fn unpack_dyn_trait(
|
49 | 83 | &self,
|
|
0 commit comments