Skip to content

Commit

Permalink
Stop using ty::Const in deref_const and destructure_const in prep…
Browse files Browse the repository at this point in the history
…aration of value trees making such operations on `ty::Const` obsolete.
  • Loading branch information
oli-obk committed Jul 12, 2021
1 parent b2a2286 commit 562cbc9
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 55 deletions.
10 changes: 4 additions & 6 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> (Bx::Value, Ty<'tcx>) {
constant
.map(|val| {
let field_ty = ty.builtin_index().unwrap();
let c = ty::Const::from_value(bx.tcx(), val, ty);
let values: Vec<_> = bx
.tcx()
.destructure_const(ty::ParamEnv::reveal_all().and(&c))
.destructure_const(ty::ParamEnv::reveal_all().and((val, ty)))
.fields
.iter()
.map(|field| {
if let Some(prim) = field.val.try_to_scalar() {
.map(|(field, field_ty)| {
if let Some(prim) = field.try_to_scalar() {
let layout = bx.layout_of(field_ty);
let scalar = match layout.abi {
Abi::Scalar(ref x) => x,
Expand All @@ -78,7 +76,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
let llval = bx.const_struct(&values, false);
(llval, c.ty)
(llval, ty)
})
.unwrap_or_else(|_| {
bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,27 @@ impl ConstantKind<'tcx> {
}
}

#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> u128 {
match self {
Self::Ty(ct) => ct.eval_bits(tcx, param_env, ty),
Self::Val(val, t) => {
assert_eq!(*t, ty);
let size = tcx
.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty))
.expect("could not normalize type")
.size;
val.try_to_scalar_int().unwrap().assert_bits(size)
}
}
}

#[inline]
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
match self {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use smallvec::SmallVec;
use std::cell::Cell;
use std::fmt::{self, Debug};

use super::{Field, SourceInfo};
use super::{interpret::ConstValue, Field, SourceInfo};

#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
Expand Down Expand Up @@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [&'tcx ty::Const<'tcx>],
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
}

/// Coverage information summarized from a MIR if instrumented for source code coverage (see
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
}
}
}

impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
}
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,16 +828,16 @@ rustc_queries! {
/// Destructure a constant ADT or array into its variant index and its
/// field values.
query destructure_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> mir::DestructuredConst<'tcx> {
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> {
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> (ConstValue<'tcx>, Ty<'tcx>) {
desc { "deref constant" }
}

Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,10 +1200,8 @@ pub trait PrettyPrinter<'tcx>:
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
);
let contents =
self.tcx().destructure_const(ty::ParamEnv::reveal_all().and((ct, ty)));
let fields = contents.fields.iter().copied();

match *ty.kind() {
Expand Down
23 changes: 14 additions & 9 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
check_const_value_eq(relation, a_val, b_val, a, b)?
check_const_value_eq(relation, a_val, b_val, a.ty, b.ty)?
}

(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
Expand Down Expand Up @@ -585,10 +585,8 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
relation: &mut R,
a_val: ConstValue<'tcx>,
b_val: ConstValue<'tcx>,
// FIXME(oli-obk): these arguments should go away with valtrees
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
// FIXME(oli-obk): this should just be `bool` with valtrees
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
) -> RelateResult<'tcx, bool> {
let tcx = relation.tcx();
Ok(match (a_val, b_val) {
Expand All @@ -610,13 +608,20 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
}

(ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
let a_destructured = tcx.destructure_const(relation.param_env().and(a));
let b_destructured = tcx.destructure_const(relation.param_env().and(b));
let a_destructured = tcx.destructure_const(relation.param_env().and((a_val, a_ty)));
let b_destructured = tcx.destructure_const(relation.param_env().and((b_val, b_ty)));

// Both the variant and each field have to be equal.
if a_destructured.variant == b_destructured.variant {
for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
relation.consts(a_field, b_field)?;
for (&(a_val, a_ty), &(b_val, b_ty)) in
iter::zip(a_destructured.fields, b_destructured.fields)
{
let is_match = check_const_value_eq(relation, a_val, b_val, a_ty, b_ty)?;
if !is_match {
let a = ty::Const::from_value(relation.tcx(), a_val, a_ty);
let b = ty::Const::from_value(relation.tcx(), b_val, b_ty);
return Err(TypeError::ConstMismatch(expected_found(relation, a, b)));
}
}

true
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_mir/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::convert::TryFrom;

use rustc_hir::Mutability;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
mir::{self, interpret::ConstAlloc},
ty::ScalarInt,
Expand Down Expand Up @@ -139,14 +139,15 @@ fn const_to_valtree_inner<'tcx>(
pub(crate) fn destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: &'tcx ty::Const<'tcx>,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> mir::DestructuredConst<'tcx> {
trace!("destructure_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.const_to_op(val, None).unwrap();
let op = ecx.const_val_to_op(val, ty, None).unwrap();

// We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match val.ty.kind() {
let (field_count, variant, down) = match op.layout.ty.kind() {
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
ty::Adt(def, _) if def.variants.is_empty() => {
return mir::DestructuredConst { variant: None, fields: &[] };
Expand All @@ -163,7 +164,7 @@ pub(crate) fn destructure_const<'tcx>(
let fields_iter = (0..field_count).map(|i| {
let field_op = ecx.operand_field(&down, i).unwrap();
let val = op_to_const(&ecx, &field_op);
ty::Const::from_value(tcx, val, field_op.layout.ty)
(val, field_op.layout.ty)
});
let fields = tcx.arena.alloc_from_iter(fields_iter);

Expand All @@ -173,11 +174,12 @@ pub(crate) fn destructure_const<'tcx>(
pub(crate) fn deref_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: &'tcx ty::Const<'tcx>,
) -> &'tcx ty::Const<'tcx> {
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> (ConstValue<'tcx>, Ty<'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 op = ecx.const_val_to_op(val, ty, None).unwrap();
let mplace = ecx.deref_operand(&op).unwrap();
if let Scalar::Ptr(ptr) = mplace.ptr {
assert_eq!(
Expand All @@ -203,5 +205,5 @@ pub(crate) fn deref_const<'tcx>(
},
};

tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
(op_to_const(&ecx, &mplace.into()), ty)
}
8 changes: 4 additions & 4 deletions compiler/rustc_mir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ pub fn provide(providers: &mut Providers) {
providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
providers.destructure_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::destructure_const(tcx, param_env, value)
let (param_env, (value, ty)) = param_env_and_value.into_parts();
const_eval::destructure_const(tcx, param_env, value, ty)
};
providers.const_to_valtree = |tcx, param_env_and_value| {
let (param_env, raw) = param_env_and_value.into_parts();
const_eval::const_to_valtree(tcx, param_env, raw)
};
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)
let (param_env, (value, ty)) = param_env_and_value.into_parts();
const_eval::deref_const(tcx, param_env, value, ty)
};
}
33 changes: 22 additions & 11 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::Field;
use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::print::with_no_trimmed_paths;
Expand Down Expand Up @@ -249,11 +250,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {

fn field_pats(
&self,
vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>,
vals: impl Iterator<Item = (ConstValue<'tcx>, Ty<'tcx>)>,
) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
let tcx = self.tcx();
vals.enumerate()
.map(|(idx, val)| {
.map(|(idx, (val, ty))| {
let field = Field::new(idx);
let val = ty::Const::from_value(tcx, val, ty);
Ok(FieldPat { field, pattern: self.recur(val, false)? })
})
.collect()
Expand Down Expand Up @@ -357,7 +360,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
PatKind::Wild
}
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
let destructured = tcx.destructure_const(param_env.and(cv));
let destructured = tcx.destructure_const(
param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
);
PatKind::Variant {
adt_def,
substs,
Expand All @@ -368,15 +373,19 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
}
}
ty::Tuple(_) | ty::Adt(_, _) => {
let destructured = tcx.destructure_const(param_env.and(cv));
let destructured = tcx.destructure_const(
param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
);
PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
}
ty::Array(..) => PatKind::Array {
prefix: tcx
.destructure_const(param_env.and(cv))
.destructure_const(
param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
)
.fields
.iter()
.map(|val| self.recur(val, false))
.map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: Vec::new(),
Expand Down Expand Up @@ -404,15 +413,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// arrays.
ty::Array(..) if !self.treat_byte_string_as_slice => {
let old = self.behind_reference.replace(true);
let array = tcx.deref_const(self.param_env.and(cv));
let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
let val = PatKind::Deref {
subpattern: Pat {
kind: Box::new(PatKind::Array {
prefix: tcx
.destructure_const(param_env.and(array))
.fields
.iter()
.map(|val| self.recur(val, false))
.map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: vec![],
Expand All @@ -430,15 +439,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// pattern.
ty::Slice(elem_ty) => {
let old = self.behind_reference.replace(true);
let array = tcx.deref_const(self.param_env.and(cv));
let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
let val = PatKind::Deref {
subpattern: Pat {
kind: Box::new(PatKind::Slice {
prefix: tcx
.destructure_const(param_env.and(array))
.fields
.iter()
.map(|val| self.recur(val, false))
.map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: vec![],
Expand Down Expand Up @@ -493,7 +502,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// we fall back to a const pattern. If we do not do this, we may end up with
// a !structural-match constant that is not of reference type, which makes it
// very hard to invoke `PartialEq::eq` on it as a fallback.
let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
let (val, ty) = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
let deref_cv = ty::Const::from_value(tcx, val, ty);
let val = match self.recur(deref_cv, false) {
Ok(subpattern) => PatKind::Deref { subpattern },
Err(_) => PatKind::Constant { value: cv },
};
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_query_impl/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,15 @@ impl<'tcx> Key for &'tcx ty::Const<'tcx> {
}
}

impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
fn query_crate_is_local(&self) -> bool {
true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}

impl<'tcx> Key for Ty<'tcx> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
Expand Down
Loading

0 comments on commit 562cbc9

Please sign in to comment.