From 34c62e0abc82b7302a3b0ee16dfe445e1330ce4c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 1 Jul 2020 11:41:38 +0200 Subject: [PATCH] Add a query for dereferencing constants of reference type --- compiler/rustc_middle/src/query/mod.rs | 8 +++++ compiler/rustc_mir/src/const_eval/mod.rs | 42 +++++++++++++++++++++++- compiler/rustc_mir/src/lib.rs | 4 +++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 44d906dada5..68bad428ea2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -749,6 +749,14 @@ rustc_queries! { desc { "destructure constant" } } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index c93feb5096b..451fa1458fd 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -2,11 +2,14 @@ use std::convert::TryFrom; +use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, +}; mod error; mod eval_queries; @@ -67,3 +70,40 @@ pub(crate) fn destructure_const<'tcx>( mir::DestructuredConst { variant, fields } } + +pub(crate) fn deref_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { + trace!("deref_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + let mplace = ecx.deref_operand(op).unwrap(); + if let Scalar::Ptr(ptr) = mplace.ptr { + assert_eq!( + ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind { + ty::Dynamic(..) => ecx.read_drop_type_from_vtable(scalar).unwrap().1, + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty }) +} diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 251037792c9..504c4ecd85c 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -60,4 +60,8 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) }; + providers.deref_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value) + }; }