diff options
| author | bors <bors@rust-lang.org> | 2022-04-28 13:18:22 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-04-28 13:18:22 +0000 |
| commit | b2c2a32870e15af02eb89de434c36535439dbf5a (patch) | |
| tree | ba0c7a3ceade56983d473ea859a3adb3af4bd973 /compiler/rustc_const_eval/src/const_eval/mod.rs | |
| parent | 3bfeffd55bbc7d653d2df7ad265746bafe595a96 (diff) | |
| parent | ef5f07256cfa4e1f43a18acb45e0d8108f8471a4 (diff) | |
Auto merge of #95976 - b-naber:valtree-constval-conversion, r=oli-obk
Implement Valtree to ConstValue conversion Once we start to use `ValTree`s in the type system we will need to be able to convert them into `ConstValue` instances, which we want to continue to use after MIR construction. r? `@oli-obk` cc `@RalfJung`
Diffstat (limited to 'compiler/rustc_const_eval/src/const_eval/mod.rs')
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/mod.rs | 136 |
1 files changed, 6 insertions, 130 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 68f9bee593f..96c18d488ee 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -3,29 +3,26 @@ use std::convert::TryFrom; use rustc_hir::Mutability; -use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::{ - mir::{self, interpret::ConstAlloc}, - ty::ScalarInt, -}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use rustc_target::abi::VariantIdx; use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, - MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, + Scalar, }; mod error; mod eval_queries; mod fn_queries; mod machine; +mod valtrees; pub use error::*; pub use eval_queries::*; pub use fn_queries::*; pub use machine::*; +pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value}; pub(crate) fn const_caller_location( tcx: TyCtxt<'_>, @@ -41,128 +38,6 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx)) } -/// Convert an evaluated constant to a type level constant -pub(crate) fn const_to_valtree<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - raw: ConstAlloc<'tcx>, -) -> Option<ty::ValTree<'tcx>> { - let ecx = mk_eval_cx( - tcx, DUMMY_SP, param_env, - // It is absolutely crucial for soundness that - // we do not read from static items or other mutable memory. - false, - ); - let place = ecx.raw_const_to_mplace(raw).unwrap(); - const_to_valtree_inner(&ecx, &place) -} - -#[instrument(skip(ecx), level = "debug")] -fn branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, - n: usize, - variant: Option<VariantIdx>, -) -> Option<ty::ValTree<'tcx>> { - let place = match variant { - Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), - None => *place, - }; - let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); - debug!(?place, ?variant); - - let fields = (0..n).map(|i| { - let field = ecx.mplace_field(&place, i).unwrap(); - const_to_valtree_inner(ecx, &field) - }); - // For enums, we prepend their variant index before the variant's fields so we can figure out - // the variant again when just seeing a valtree. - let branches = variant.into_iter().chain(fields); - Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?))) -} - -fn slice_branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, -) -> Option<ty::ValTree<'tcx>> { - let n = place.len(&ecx.tcx()).expect(&format!("expected to use len of place {:?}", place)); - let branches = (0..n).map(|i| { - let place_elem = ecx.mplace_index(place, i).unwrap(); - const_to_valtree_inner(ecx, &place_elem) - }); - - Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?))) -} - -#[instrument(skip(ecx), level = "debug")] -fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, -) -> Option<ty::ValTree<'tcx>> { - match place.layout.ty.kind() { - ty::FnDef(..) => Some(ty::ValTree::zst()), - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(&place.into()).unwrap(); - let val = val.to_scalar().unwrap(); - Some(ty::ValTree::Leaf(val.assert_int())) - } - - // Raw pointers are not allowed in type level constants, as we cannot properly test them for - // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). - // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to - // agree with runtime equality tests. - ty::FnPtr(_) | ty::RawPtr(_) => None, - - ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); - debug!(?derefd_place); - - const_to_valtree_inner(ecx, &derefd_place) - } - - ty::Str | ty::Slice(_) | ty::Array(_, _) => { - let valtree = slice_branches(ecx, place); - debug!(?valtree); - - valtree - } - // Trait objects are not allowed in type level constants, as we have no concept for - // resolving their backing type, even if we can do that at const eval time. We may - // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, - // but it is unclear if this is useful. - ty::Dynamic(..) => None, - - ty::Tuple(substs) => branches(ecx, place, substs.len(), None), - - ty::Adt(def, _) => { - if def.variants().is_empty() { - bug!("uninhabited types should have errored and never gotten converted to valtree") - } - - let variant = ecx.read_discriminant(&place.into()).unwrap().1; - - branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant)) - } - - ty::Never - | ty::Error(_) - | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Projection(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - // FIXME(oli-obk): we could look behind opaque types - | ty::Opaque(..) - | ty::Infer(_) - // FIXME(oli-obk): we can probably encode closures just like structs - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) => None, - } -} - /// This function should never fail for validated constants. However, it is also invoked from the /// pretty printer which might attempt to format invalid constants and in that case it might fail. pub(crate) fn try_destructure_const<'tcx>( @@ -202,6 +77,7 @@ pub(crate) fn try_destructure_const<'tcx>( Ok(mir::DestructuredConst { variant, fields }) } +#[instrument(skip(tcx), level = "debug")] pub(crate) fn deref_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, |
