|
2 | 2 |
|
3 | 3 | use std::convert::TryFrom;
|
4 | 4 |
|
| 5 | +use rustc_hir::lang_items::LangItem; |
5 | 6 | use rustc_hir::Mutability;
|
6 |
| -use rustc_middle::ty::{self, TyCtxt}; |
7 |
| -use rustc_middle::{ |
8 |
| - mir::{self, interpret::ConstAlloc}, |
9 |
| - ty::ScalarInt, |
10 |
| -}; |
| 7 | +use rustc_middle::mir::{self, interpret::ConstAlloc}; |
| 8 | +use rustc_middle::ty::layout::LayoutOf; |
| 9 | +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; |
11 | 10 | use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
|
| 11 | +use rustc_target::abi::Size; |
12 | 12 |
|
13 | 13 | use crate::interpret::{
|
14 |
| - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, |
| 14 | + self, intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, |
15 | 15 | MemPlaceMeta, Scalar,
|
16 | 16 | };
|
17 | 17 |
|
@@ -39,6 +39,87 @@ pub(crate) fn const_caller_location(
|
39 | 39 | ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
|
40 | 40 | }
|
41 | 41 |
|
| 42 | +pub(crate) fn const_type_id<'tcx>( |
| 43 | + tcx: TyCtxt<'tcx>, |
| 44 | + param_env: ty::ParamEnv<'tcx>, |
| 45 | + ty: Ty<'tcx>, |
| 46 | +) -> ConstValue<'tcx> { |
| 47 | + trace!("const_type_id: {}", ty); |
| 48 | + |
| 49 | + // Compute (logical) `TypeId` field values, before trying to encode them. |
| 50 | + let hash = tcx.type_id_hash(ty); |
| 51 | + let mangling = tcx.type_id_mangling(param_env.and(ty)).name; |
| 52 | + |
| 53 | + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); |
| 54 | + |
| 55 | + let type_id_ty = tcx.type_of(tcx.require_lang_item(LangItem::TypeId, None)); |
| 56 | + let type_id_layout = ecx.layout_of(type_id_ty).unwrap(); |
| 57 | + |
| 58 | + // Encode `TypeId` field values, before putting together the allocation. |
| 59 | + let hash_val = Scalar::from_u64(hash); |
| 60 | + let mangling_val = { |
| 61 | + let mangling_len = u64::try_from(mangling.len()).unwrap(); |
| 62 | + let mangling_len_val = Scalar::from_machine_usize(mangling_len, &ecx); |
| 63 | + |
| 64 | + // The field is `mangling: &TypeManglingStr`, get `TypeManglingStr` from it. |
| 65 | + let mangling_field_ty = type_id_layout.field(&ecx, 1).ty; |
| 66 | + let type_mangling_str_ty = mangling_field_ty.builtin_deref(true).unwrap().ty; |
| 67 | + |
| 68 | + // Allocate memory for `TypeManglingStr` struct. |
| 69 | + let type_mangling_str_layout = ecx.layout_of(type_mangling_str_ty).unwrap(); |
| 70 | + let type_mangling_str_place = { |
| 71 | + // NOTE(eddyb) this similar to the `ecx.allocate(...)` used below |
| 72 | + // for `type_id_place`, except with an additional size for the |
| 73 | + // string bytes (`mangling`) being added to the `TypeManglingStr` |
| 74 | + // (which is unsized, using an `extern { type }` tail). |
| 75 | + let layout = type_mangling_str_layout; |
| 76 | + let size = layout.size + Size::from_bytes(mangling_len); |
| 77 | + let ptr = ecx |
| 78 | + .allocate_ptr(size, layout.align.abi, interpret::MemoryKind::IntrinsicGlobal) |
| 79 | + .unwrap(); |
| 80 | + MPlaceTy::from_aligned_ptr(ptr.into(), layout) |
| 81 | + }; |
| 82 | + |
| 83 | + // Initialize `TypeManglingStr` fields. |
| 84 | + ecx.write_scalar( |
| 85 | + mangling_len_val, |
| 86 | + &ecx.mplace_field(&type_mangling_str_place, 0).unwrap().into(), |
| 87 | + ) |
| 88 | + .unwrap(); |
| 89 | + ecx.write_bytes_ptr( |
| 90 | + ecx.mplace_field(&type_mangling_str_place, 1).unwrap().ptr, |
| 91 | + mangling.bytes(), |
| 92 | + ) |
| 93 | + .unwrap(); |
| 94 | + |
| 95 | + // `&TypeManglingStr` has no metadata, thanks to the length being stored |
| 96 | + // behind the reference (in the first field of `TypeManglingStr`). |
| 97 | + type_mangling_str_place.to_ref(&ecx).to_scalar().unwrap() |
| 98 | + }; |
| 99 | + |
| 100 | + // FIXME(eddyb) everything below would be unnecessary if `ConstValue` could |
| 101 | + // hold a pair of `Scalar`s, or if we moved to valtrees. |
| 102 | + |
| 103 | + // Allocate memory for `TypeId` struct. |
| 104 | + let type_id_place = |
| 105 | + ecx.allocate(type_id_layout, interpret::MemoryKind::IntrinsicGlobal).unwrap(); |
| 106 | + |
| 107 | + // Initialize `TypeId` fields. |
| 108 | + ecx.write_scalar(hash_val, &ecx.mplace_field(&type_id_place, 0).unwrap().into()).unwrap(); |
| 109 | + ecx.write_scalar(mangling_val, &ecx.mplace_field(&type_id_place, 1).unwrap().into()).unwrap(); |
| 110 | + |
| 111 | + // Convert the `TypeId` allocation from being in `ecx`, to a global `ConstValue`. |
| 112 | + if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &type_id_place).is_err() { |
| 113 | + bug!("intern_const_alloc_recursive should not error in this case") |
| 114 | + } |
| 115 | + let (type_id_alloc_id, type_id_offset) = |
| 116 | + type_id_place.ptr.into_pointer_or_addr().unwrap().into_parts(); |
| 117 | + ConstValue::ByRef { |
| 118 | + alloc: tcx.global_alloc(type_id_alloc_id).unwrap_memory(), |
| 119 | + offset: type_id_offset, |
| 120 | + } |
| 121 | +} |
| 122 | + |
42 | 123 | /// Convert an evaluated constant to a type level constant
|
43 | 124 | pub(crate) fn const_to_valtree<'tcx>(
|
44 | 125 | tcx: TyCtxt<'tcx>,
|
|
0 commit comments