From 562cbc9c5b3121b1f29d06dc059ee66652bc476f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 1 Apr 2021 14:03:40 +0000 Subject: [PATCH] Stop using ty::Const in `deref_const` and `destructure_const` in preparation of value trees making such operations on `ty::Const` obsolete. --- .../rustc_codegen_ssa/src/mir/constant.rs | 10 +++--- compiler/rustc_middle/src/mir/mod.rs | 21 ++++++++++++ compiler/rustc_middle/src/mir/query.rs | 4 +-- .../rustc_middle/src/mir/type_foldable.rs | 10 ++++++ compiler/rustc_middle/src/query/mod.rs | 6 ++-- compiler/rustc_middle/src/ty/print/pretty.rs | 6 ++-- compiler/rustc_middle/src/ty/relate.rs | 23 ++++++++----- compiler/rustc_mir/src/const_eval/mod.rs | 20 ++++++----- compiler/rustc_mir/src/lib.rs | 8 ++--- .../src/thir/pattern/const_to_pat.rs | 33 ++++++++++++------- compiler/rustc_query_impl/src/keys.rs | 9 +++++ .../clippy/clippy_lints/src/non_copy_const.rs | 14 ++++---- 12 files changed, 109 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index fa8a53e60b169..f3e4b32300b4f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -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, @@ -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"); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 672686410f9bf..3181ff66ab7f8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -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 { match self { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 4fb737f463a86..685ac89ee0bd8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -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 { @@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option, - 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 diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index f3124e5bf424e..c7bcae947ef98 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { } } } + +impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> { + fn super_fold_with>(self, _folder: &mut F) -> Self { + self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9a2f1149316e2..471bb68a7db52 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -828,7 +828,7 @@ 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" } } @@ -836,8 +836,8 @@ rustc_queries! { /// 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" } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 44fa4eb71d801..1ca7fef102873 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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() { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3f426b13688fe..d1ab23b6fd3e8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -546,7 +546,7 @@ pub fn super_relate_consts>( (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)) @@ -585,10 +585,8 @@ fn check_const_value_eq>( 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) { @@ -610,13 +608,20 @@ fn check_const_value_eq>( } (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 diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 6a514e9f62fce..6609205616dee 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -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, @@ -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: &[] }; @@ -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); @@ -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!( @@ -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) } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index a58ded9cfd3a4..3303ec4ebf71c 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -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) }; } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 369fff00456a7..dffadc7aab1d6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -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; @@ -249,11 +250,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn field_pats( &self, - vals: impl Iterator>, + vals: impl Iterator, Ty<'tcx>)>, ) -> Result>, 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() @@ -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, @@ -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::>()?, slice: None, suffix: Vec::new(), @@ -404,7 +413,7 @@ 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 { @@ -412,7 +421,7 @@ impl<'a, 'tcx> ConstToPat<'a, '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::>()?, slice: None, suffix: vec![], @@ -430,7 +439,7 @@ 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 { @@ -438,7 +447,7 @@ impl<'a, 'tcx> ConstToPat<'a, '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::>()?, slice: None, suffix: vec![], @@ -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 }, }; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index b3cc7de4662a5..5c711673e6240 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -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 { diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index d775cd7c7f740..15f4c04857651 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, AssocKind, Const, Ty}; +use rustc_middle::ty::{self, AssocKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -129,15 +129,15 @@ fn is_value_unfrozen_raw<'tcx>( result: Result, ErrorHandled>, ty: Ty<'tcx>, ) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { - match val.ty.kind() { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { - let val = cx.tcx.destructure_const(cx.param_env.and(val)); - val.fields.iter().any(|field| inner(cx, field)) - }, + let val = cx.tcx.destructure_const(cx.param_env.and((val, ty))); + val.fields.iter().any(|&(f, f_ty)| inner(cx, f, f_ty)) + } _ => false, } } @@ -167,7 +167,7 @@ fn is_value_unfrozen_raw<'tcx>( // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). err == ErrorHandled::TooGeneric }, - |val| inner(cx, Const::from_value(cx.tcx, val, ty)), + |val| inner(cx, val, ty), ) }