diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index b0639cf9e15..9d93370b7d0 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -8,7 +8,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, Scalar, }; -use rustc_middle::ty::{Const, ConstKind}; +use rustc_middle::ty::ConstKind; use cranelift_codegen::ir::GlobalValueData; use cranelift_module::*; @@ -39,7 +39,10 @@ impl ConstantCx { pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { let mut all_constants_ok = true; for constant in &fx.mir.required_consts { - let const_ = fx.monomorphize(constant.literal); + let const_ = match fx.monomorphize(constant.literal) { + ConstantKind::Ty(ct) => ct, + ConstantKind::Val(..) => continue, + }; match const_.val { ConstKind::Value(_) => {} ConstKind::Unevaluated(def, ref substs, promoted) => { @@ -113,19 +116,17 @@ pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let const_ = fx.monomorphize(constant.literal); + let const_ = match fx.monomorphize(constant.literal) { + ConstantKind::Ty(ct) => ct, + ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), + }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, ConstKind::Unevaluated(def, ref substs, promoted) if fx.tcx.is_static(def.did) => { assert!(substs.is_empty()); assert!(promoted.is_none()); - return codegen_static_ref( - fx, - def.did, - fx.layout_of(fx.monomorphize(&constant.literal.ty)), - ) - .to_cvalue(fx); + return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); } ConstKind::Unevaluated(def, ref substs, promoted) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), def, substs, promoted, None) { @@ -422,11 +423,14 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant pub(crate) fn mir_operand_get_const_val<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, operand: &Operand<'tcx>, -) -> Option<&'tcx Const<'tcx>> { +) -> Option> { match operand { Operand::Copy(_) | Operand::Move(_) => None, - Operand::Constant(const_) => { - Some(fx.monomorphize(const_.literal).eval(fx.tcx, ParamEnv::reveal_all())) - } + Operand::Constant(const_) => match const_.literal { + ConstantKind::Ty(const_) => { + fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() + } + ConstantKind::Val(val, _) => Some(val), + }, } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 0692da397eb..83c91f789cd 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -53,7 +53,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) { let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); - let flt_cc = match kind_const.val.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { + let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { 0 => FloatCC::Equal, 1 => FloatCC::LessThan, 2 => FloatCC::LessThanOrEqual, @@ -84,7 +84,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.psrli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; @@ -94,7 +94,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.pslli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 1f8eeb1e714..d17136080fe 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -85,8 +85,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( use rustc_middle::mir::interpret::*; let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const"); - let idx_bytes = match idx_const.val { - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => { + let idx_bytes = match idx_const { + ConstValue::ByRef { alloc, offset } => { let ptr = Pointer::new(AllocId(0 /* dummy */), offset); let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */); alloc.get_bytes(fx, ptr, size).unwrap() @@ -130,7 +130,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); @@ -159,7 +159,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 31d5c87182d..38e928145a8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -231,7 +231,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { let check = match terminator.kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => { - match *c.literal.ty.kind() { + match *c.ty().kind() { ty::FnDef(did, _) => Some((did, args)), _ => None, } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a8dda100763..04225ddd36f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -635,12 +635,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") { if let mir::Operand::Constant(constant) = arg { let c = self.eval_mir_constant(constant); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - constant.span, - constant.literal.ty, - c, - ); + let (llval, ty) = + self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c); return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty), @@ -830,7 +826,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let const_value = self .eval_mir_constant(constant) .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved")); - let ty = constant.literal.ty; + let ty = constant.ty(); let size = bx.layout_of(ty).size; let scalar = match const_value { ConstValue::Scalar(s) => s, @@ -864,7 +860,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(value.literal); - if let ty::FnDef(def_id, substs) = *literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index b79a221a0e7..aa41acc3578 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -16,7 +16,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { let val = self.eval_mir_constant(constant)?; - let ty = self.monomorphize(constant.literal.ty); + let ty = self.monomorphize(constant.ty()); Ok(OperandRef::from_const(bx, val, ty)) } @@ -24,7 +24,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { - match self.monomorphize(constant.literal).val { + let ct = self.monomorphize(constant.literal); + let ct = match ct { + mir::ConstantKind::Ty(ct) => ct, + mir::ConstantKind::Val(val, _) => return Ok(val), + }; + match ct.val { ty::ConstKind::Unevaluated(def, substs, promoted) => self .cx .tcx() diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index ea59e183118..a3f20abc82d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (var_ty, var_kind) } mir::VarDebugInfoContents::Const(c) => { - let ty = self.monomorphize(c.literal.ty); + let ty = self.monomorphize(c.ty()); (ty, VariableKind::LocalVariable) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index a07ccd4d2b5..5172dfd041a 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; use rustc_apfloat::{ @@ -8,12 +8,12 @@ use rustc_apfloat::{ use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; +use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. -#[derive(Clone, HashStable, TyEncodable, TyDecodable, Debug)] +#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)] pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). @@ -47,6 +47,27 @@ pub enum ConstValue<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ConstValue<'_>, 32); +impl From for ConstValue<'tcx> { + fn from(s: Scalar) -> Self { + Self::Scalar(s) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { + type Lifted = ConstValue<'tcx>; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { + Some(match self { + ConstValue::Scalar(s) => ConstValue::Scalar(s), + ConstValue::Slice { data, start, end } => { + ConstValue::Slice { data: tcx.lift(data)?, start, end } + } + ConstValue::ByRef { alloc, offset } => { + ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset } + } + }) + } +} + impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option { @@ -56,20 +77,20 @@ impl<'tcx> ConstValue<'tcx> { } } + pub fn try_to_scalar_int(&self) -> Option { + Some(self.try_to_scalar()?.assert_int()) + } + pub fn try_to_bits(&self, size: Size) -> Option { - self.try_to_scalar()?.to_bits(size).ok() + self.try_to_scalar_int()?.to_bits(size).ok() } pub fn try_to_bool(&self) -> Option { - match self.try_to_bits(Size::from_bytes(1))? { - 0 => Some(false), - 1 => Some(true), - _ => None, - } + self.try_to_scalar_int()?.try_into().ok() } pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option { - Some(self.try_to_bits(tcx.data_layout.pointer_size)? as u64) + self.try_to_scalar_int()?.try_to_machine_usize(tcx).ok() } pub fn try_to_bits_for_ty( @@ -503,6 +524,13 @@ impl From> for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(ptr: ScalarInt) -> Self { + Scalar::Int(ptr) + } +} + #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] pub enum ScalarMaybeUninit { Scalar(Scalar), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f6952667494..90fda9ec91c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -11,12 +11,12 @@ use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; -use crate::ty::{AdtDef, InstanceDef, Region, UserTypeAnnotationIndex}; +use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; @@ -30,6 +30,7 @@ use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::borrow::Cow; +use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; use std::ops::{ControlFlow, Index, IndexMut}; use std::slice; @@ -2032,7 +2033,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: ConstantKind::Ty(ty::Const::zero_sized(tcx, ty)), }) } @@ -2063,7 +2064,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::from_scalar(tcx, val, ty), + literal: ConstantKind::Val(val.into(), ty), }) } @@ -2405,12 +2406,21 @@ pub struct Constant<'tcx> { /// Needed for NLL to impose user-given type constraints. pub user_ty: Option, - pub literal: &'tcx ty::Const<'tcx>, + pub literal: ConstantKind<'tcx>, +} + +#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] +pub enum ConstantKind<'tcx> { + /// This constant came from the type system + Ty(&'tcx ty::Const<'tcx>), + /// This constant cannot go back into the type system, as it represents + /// something the type system cannot handle (e.g. pointers). + Val(interpret::ConstValue<'tcx>, Ty<'tcx>), } impl Constant<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option { - match self.literal.val.try_to_scalar() { + match self.literal.const_for_ty()?.val.try_to_scalar() { Some(Scalar::Ptr(ptr)) => match tcx.global_alloc(ptr.alloc_id) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -2421,6 +2431,94 @@ impl Constant<'tcx> { _ => None, } } + pub fn ty(&self) -> Ty<'tcx> { + self.literal.ty() + } +} + +impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { + fn from(ct: &'tcx ty::Const<'tcx>) -> Self { + Self::Ty(ct) + } +} + +impl ConstantKind<'tcx> { + /// Returns `None` if the constant is not trivially safe for use in the type system. + pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> { + match self { + ConstantKind::Ty(c) => Some(c), + ConstantKind::Val(..) => None, + } + } + + pub fn ty(&self) -> Ty<'tcx> { + match self { + ConstantKind::Ty(c) => c.ty, + ConstantKind::Val(_, ty) => ty, + } + } + + #[inline] + pub fn try_to_value(self) -> Option> { + match self { + ConstantKind::Ty(c) => c.val.try_to_value(), + ConstantKind::Val(val, _) => Some(val), + } + } + + #[inline] + pub fn try_to_scalar(self) -> Option { + self.try_to_value()?.try_to_scalar() + } + + #[inline] + pub fn try_to_scalar_int(self) -> Option { + Some(self.try_to_value()?.try_to_scalar()?.assert_int()) + } + + #[inline] + pub fn try_to_bits(self, size: Size) -> Option { + self.try_to_scalar_int()?.to_bits(size).ok() + } + + #[inline] + pub fn try_to_bool(self) -> Option { + self.try_to_scalar_int()?.try_into().ok() + } + + #[inline] + pub fn try_eval_bits( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Option { + match self { + Self::Ty(ct) => ct.try_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)).ok()?.size; + val.try_to_bits(size) + } + } + } + + #[inline] + pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { + match self { + Self::Ty(ct) => ct.try_eval_bool(tcx, param_env), + Self::Val(val, _) => val.try_to_bool(), + } + } + + #[inline] + pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { + match self { + Self::Ty(ct) => ct.try_eval_usize(tcx, param_env), + Self::Val(val, _) => val.try_to_machine_usize(tcx), + } + } } /// A collection of projections into user types. @@ -2606,11 +2704,14 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.literal.ty.kind() { + match self.ty().kind() { ty::FnDef(..) => {} _ => write!(fmt, "const ")?, } - pretty_print_const(self.literal, fmt, true) + match self.literal { + ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), + ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + } } } @@ -2629,6 +2730,23 @@ fn pretty_print_const( }) } +fn pretty_print_const_value( + val: interpret::ConstValue<'tcx>, + ty: Ty<'tcx>, + fmt: &mut Formatter<'_>, + print_types: bool, +) -> fmt::Result { + use crate::ty::print::PrettyPrinter; + ty::tls::with(|tcx| { + let val = tcx.lift(val).unwrap(); + let ty = tcx.lift(ty).unwrap(); + let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); + cx.print_alloc_ids = true; + cx.pretty_print_const_value(val, ty, print_types)?; + Ok(()) + }) +} + impl<'tcx> graph::DirectedGraph for Body<'tcx> { type Node = BasicBlock; } diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 3961fd938be..6e819145976 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - &Operand::Constant(ref c) => c.literal.ty, + &Operand::Constant(ref c) => c.literal.ty(), } } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 6fabddbd149..cb599277270 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -342,6 +342,23 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { } } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.literal.visit_with(visitor) + self.literal.visit_with(visitor)?; + self.user_ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { + fn super_fold_with>(self, folder: &mut F) -> Self { + match self { + ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)), + ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { + match *self { + ConstantKind::Ty(c) => c.visit_with(visitor), + ConstantKind::Val(_, t) => t.visit_with(visitor), + } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 4e81612c0b9..be248ccabda 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -871,7 +871,10 @@ macro_rules! make_mir_visitor { self.visit_span(span); drop(user_ty); // no visit method for this - self.visit_const(literal, location); + match literal { + ConstantKind::Ty(ct) => self.visit_const(ct, location), + ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), + } } fn super_span(&mut self, _span: & $($mutability)? Span) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c5697ff1ce1..872cf1ed194 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -785,6 +785,14 @@ rustc_queries! { cache_on_disk_if { true } } + /// Convert an evaluated constant to a type level constant or + /// return `None` if that is not possible. + query const_to_valtree( + key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> + ) -> Option> { + desc { "destructure constant" } + } + /// Destructure a constant ADT or array into its variant index and its /// field values. query destructure_const( diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 73ad87a9ef2..f796534c2e1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -333,6 +333,16 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> { } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index e7b2c9efd63..622f8e8ff6c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -10,9 +10,11 @@ use rustc_macros::HashStable; mod int; mod kind; +mod valtree; pub use int::*; pub use kind::*; +pub use valtree::*; /// Typed constant value. #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 63e95f25bb7..8ed8ea6a0bc 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -5,6 +5,8 @@ use rustc_target::abi::{Size, TargetDataLayout}; use std::convert::{TryFrom, TryInto}; use std::fmt; +use crate::ty::TyCtxt; + #[derive(Copy, Clone)] /// A type for representing any integer. Only used for printing. pub struct ConstInt { @@ -239,6 +241,11 @@ impl ScalarInt { Err(self.size()) } } + + #[inline] + pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Result { + Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64) + } } macro_rules! from { @@ -277,6 +284,18 @@ macro_rules! try_from { from!(u8, u16, u32, u64, u128, bool); try_from!(u8, u16, u32, u64, u128); +impl TryFrom for bool { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result { + int.to_bits(Size::from_bytes(1)).and_then(|u| match u { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Size::from_bytes(1)), + }) + } +} + impl From for ScalarInt { #[inline] fn from(c: char) -> Self { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 98c215407a8..43e22ce8f87 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::mir::interpret::ConstValue; use crate::mir::interpret::Scalar; use crate::mir::Promoted; @@ -9,6 +11,8 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_target::abi::Size; +use super::ScalarInt; + /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] @@ -51,14 +55,19 @@ impl<'tcx> ConstKind<'tcx> { self.try_to_value()?.try_to_scalar() } + #[inline] + pub fn try_to_scalar_int(self) -> Option { + Some(self.try_to_value()?.try_to_scalar()?.assert_int()) + } + #[inline] pub fn try_to_bits(self, size: Size) -> Option { - self.try_to_value()?.try_to_bits(size) + self.try_to_scalar_int()?.to_bits(size).ok() } #[inline] pub fn try_to_bool(self) -> Option { - self.try_to_value()?.try_to_bool() + self.try_to_scalar_int()?.try_into().ok() } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs new file mode 100644 index 00000000000..f1b78c87632 --- /dev/null +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -0,0 +1,34 @@ +use super::ScalarInt; +use rustc_macros::HashStable; + +#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] +#[derive(HashStable)] +/// This datastructure is used to represent the value of constants used in the type system. +/// +/// We explicitly choose a different datastructure from the way values are processed within +/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have +/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. +/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different +/// `AllocId`s point to equal values. So we may end up with different representations for +/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will +/// have arbitrary values within that padding, even if the values of the struct are the same. +/// +/// `ValTree` does not have this problem with representation, as it only contains integers or +/// lists of (nested) `ValTree`. +pub enum ValTree<'tcx> { + /// ZSTs, integers, `bool`, `char` are represented as scalars. + /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values + /// of these types have the same representation. + Leaf(ScalarInt), + /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by + /// listing their fields' values in order. + /// Enums are represented by storing their discriminant as a field, followed by all + /// the fields of the variant. + Branch(&'tcx [ValTree<'tcx>]), +} + +impl ValTree<'tcx> { + pub fn zst() -> Self { + Self::Branch(&[]) + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 61865a67d25..9c0048d96da 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -95,6 +95,8 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, + /// Const allocations. + allocation: InternedSet<'tcx, Allocation>, } impl<'tcx> CtxtInterners<'tcx> { @@ -112,6 +114,7 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), + allocation: Default::default(), } } @@ -1041,9 +1044,6 @@ pub struct GlobalCtxt<'tcx> { /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>, - /// Stores the value of constants (and deduplicates the actual memory) - allocation_interner: ShardedHashMap<&'tcx Allocation, ()>, - /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock>, @@ -1086,7 +1086,10 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation { - self.allocation_interner.intern(alloc, |alloc| self.arena.alloc(alloc)) + self.interners + .allocation + .intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc))) + .0 } /// Allocates a read-only byte or string literal for `mir::interpret`. @@ -1205,7 +1208,6 @@ impl<'tcx> TyCtxt<'tcx> { layout_interner: Default::default(), stability_interner: Default::default(), const_stability_interner: Default::default(), - allocation_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames.clone()), } @@ -1641,6 +1643,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} +nop_lift! {allocation; &'a Allocation => &'tcx Allocation} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} @@ -1931,7 +1934,7 @@ impl<'tcx> TyCtxt<'tcx> { "Const Stability interner: #{}", self.0.const_stability_interner.len() )?; - writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?; + writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?; writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; Ok(()) @@ -2032,6 +2035,26 @@ impl<'tcx> Borrow> for Interned<'tcx, Const<'tcx>> { } } +impl<'tcx> Borrow for Interned<'tcx, Allocation> { + fn borrow<'a>(&'a self) -> &'a Allocation { + &self.0 + } +} + +impl<'tcx> PartialEq for Interned<'tcx, Allocation> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl<'tcx> Eq for Interned<'tcx, Allocation> {} + +impl<'tcx> Hash for Interned<'tcx, Allocation> { + fn hash(&self, s: &mut H) { + self.0.hash(s) + } +} + macro_rules! direct_interners { ($($name:ident: $method:ident($ty:ty),)+) => { $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f5aef108927..5bbf7b35d3d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -55,7 +55,7 @@ pub use rustc_type_ir::*; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; -pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt}; +pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, ValTree}; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 53c164d44b3..7946d170064 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -956,32 +956,40 @@ pub trait PrettyPrinter<'tcx>: } fn pretty_print_const_scalar( - mut self, + self, scalar: Scalar, ty: Ty<'tcx>, print_ty: bool, + ) -> Result { + match scalar { + Scalar::Ptr(ptr) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty), + Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty), + } + } + + fn pretty_print_const_scalar_ptr( + mut self, + ptr: Pointer, + ty: Ty<'tcx>, + print_ty: bool, ) -> Result { define_scoped_cx!(self); - match (scalar, &ty.kind()) { + match ty.kind() { // Byte strings (&[u8; N]) - ( - Scalar::Ptr(ptr), - ty::Ref( - _, - ty::TyS { - kind: - ty::Array( - ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, - ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(int)), - .. - }, - ), - .. - }, - _, - ), + ty::Ref( + _, + ty::TyS { + kind: + ty::Array( + ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, + ty::Const { + val: ty::ConstKind::Value(ConstValue::Scalar(int)), .. + }, + ), + .. + }, + _, ) => match self.tcx().get_global_alloc(ptr.alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let bytes = int.assert_bits(self.tcx().data_layout.pointer_size); @@ -997,39 +1005,7 @@ pub trait PrettyPrinter<'tcx>: Some(GlobalAlloc::Function(_)) => p!(""), None => p!(""), }, - // Bool - (Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), - (Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), - // Float - (Scalar::Int(int), ty::Float(ty::FloatTy::F32)) => { - p!(write("{}f32", Single::try_from(int).unwrap())) - } - (Scalar::Int(int), ty::Float(ty::FloatTy::F64)) => { - p!(write("{}f64", Double::try_from(int).unwrap())) - } - // Int - (Scalar::Int(int), ty::Uint(_) | ty::Int(_)) => { - let int = - ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral()); - if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) } - } - // Char - (Scalar::Int(int), ty::Char) if char::try_from(int).is_ok() => { - p!(write("{:?}", char::try_from(int).unwrap())) - } - // Raw pointers - (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => { - let data = int.assert_bits(self.tcx().data_layout.pointer_size); - self = self.typed_value( - |mut this| { - write!(this, "0x{:x}", data)?; - Ok(this) - }, - |this| this.print_type(ty), - " as ", - )?; - } - (Scalar::Ptr(ptr), ty::FnPtr(_)) => { + ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). match self.tcx().get_global_alloc(ptr.alloc_id) { @@ -1043,12 +1019,61 @@ pub trait PrettyPrinter<'tcx>: _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?, } } + // Any pointer values not covered by a branch above + _ => { + self = self.pretty_print_const_pointer(ptr, ty, print_ty)?; + } + } + Ok(self) + } + + fn pretty_print_const_scalar_int( + mut self, + int: ScalarInt, + ty: Ty<'tcx>, + print_ty: bool, + ) -> Result { + define_scoped_cx!(self); + + match ty.kind() { + // Bool + ty::Bool if int == ScalarInt::FALSE => p!("false"), + ty::Bool if int == ScalarInt::TRUE => p!("true"), + // Float + ty::Float(ty::FloatTy::F32) => { + p!(write("{}f32", Single::try_from(int).unwrap())) + } + ty::Float(ty::FloatTy::F64) => { + p!(write("{}f64", Double::try_from(int).unwrap())) + } + // Int + ty::Uint(_) | ty::Int(_) => { + let int = + ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral()); + if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) } + } + // Char + ty::Char if char::try_from(int).is_ok() => { + p!(write("{:?}", char::try_from(int).unwrap())) + } + // Raw pointers + ty::RawPtr(_) | ty::FnPtr(_) => { + let data = int.assert_bits(self.tcx().data_layout.pointer_size); + self = self.typed_value( + |mut this| { + write!(this, "0x{:x}", data)?; + Ok(this) + }, + |this| this.print_type(ty), + " as ", + )?; + } // For function type zsts just printing the path is enough - (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { + ty::FnDef(d, s) if int == ScalarInt::ZST => { p!(print_value_path(*d, s)) } // Nontrivial types with scalar bit representation - (Scalar::Int(int), _) => { + _ => { let print = |mut this: Self| { if int.size() == Size::ZERO { write!(this, "transmute(())")?; @@ -1063,10 +1088,6 @@ pub trait PrettyPrinter<'tcx>: print(self)? }; } - // Any pointer values not covered by a branch above - (Scalar::Ptr(p), _) => { - self = self.pretty_print_const_pointer(p, ty, print_ty)?; - } } Ok(self) } diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 51a214bc07b..48e777f7158 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -14,8 +14,8 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; +use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; -use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index f21545447b2..436ca4c0578 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -4,13 +4,12 @@ //! types or regions but can be other things. Examples of type relations are //! subtyping, type equality, etc. -use crate::mir::interpret::{get_slice_bytes, ConstValue}; +use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; -use rustc_span::DUMMY_SP; use rustc_target::spec::abi; use std::iter; @@ -498,104 +497,41 @@ pub fn super_relate_consts>( debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val; + // FIXME(oli-obk): once const generics can have generic types, this assertion + // will likely get triggered. Move to `normalize_erasing_regions` at that point. + assert_eq!( + tcx.erase_regions(a.ty), + tcx.erase_regions(b.ty), + "cannot relate constants of different types" + ); - // FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`. - // We could probably always assert it early, as const generic parameters - // are not allowed to depend on other generic parameters, i.e. are concrete. - // (although there could be normalization differences) + let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()); + let a = eagerly_eval(a); + let b = eagerly_eval(b); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. - let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) { + let is_match = match (a.val, b.val) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } - (ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)), + (ty::ConstKind::Error(_), _) => return Ok(a), + (_, ty::ConstKind::Error(_)) => return Ok(b), - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - return Ok(a); - } - (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) if p1 == p2 => { - return Ok(a); - } + (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)) => { - let new_val = match (a_val, b_val) { - (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { - if a_val == b_val { - Ok(ConstValue::Scalar(a_val)) - } else if let ty::FnPtr(_) = a.ty.kind() { - let a_instance = tcx.global_alloc(a_val.assert_ptr().alloc_id).unwrap_fn(); - let b_instance = tcx.global_alloc(b_val.assert_ptr().alloc_id).unwrap_fn(); - if a_instance == b_instance { - Ok(ConstValue::Scalar(a_val)) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } - - (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { - let a_bytes = get_slice_bytes(&tcx, a_val); - let b_bytes = get_slice_bytes(&tcx, b_val); - if a_bytes == b_bytes { - Ok(a_val) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } - - (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - match a.ty.kind() { - ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { - let a_destructured = tcx.destructure_const(relation.param_env().and(a)); - let b_destructured = tcx.destructure_const(relation.param_env().and(b)); - - // Both the variant and each field have to be equal. - if a_destructured.variant == b_destructured.variant { - for (a_field, b_field) in - a_destructured.fields.iter().zip(b_destructured.fields.iter()) - { - relation.consts(a_field, b_field)?; - } - - Ok(a_val) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } - // FIXME(const_generics): There are probably some `TyKind`s - // which should be handled here. - _ => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected consts: a: {:?}, b: {:?}", a, b), - ); - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } - } - - _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), - }; - - new_val.map(ty::ConstKind::Value) + check_const_value_eq(relation, a_val, b_val, a, b)? } ( ty::ConstKind::Unevaluated(a_def, a_substs, None), ty::ConstKind::Unevaluated(b_def, b_substs, None), ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { - if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { - Ok(a.val) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } + tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` @@ -607,11 +543,64 @@ pub fn super_relate_consts>( ) if a_def == b_def && a_promoted == b_promoted => { let substs = relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; - Ok(ty::ConstKind::Unevaluated(a_def, substs, a_promoted)) + return Ok(tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(a_def, substs, a_promoted), + ty: a.ty, + })); } - _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), + _ => false, }; - new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) + if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } +} + +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 +) -> RelateResult<'tcx, bool> { + let tcx = relation.tcx(); + Ok(match (a_val, b_val) { + (ConstValue::Scalar(Scalar::Int(a_val)), ConstValue::Scalar(Scalar::Int(b_val))) => { + a_val == b_val + } + (ConstValue::Scalar(Scalar::Ptr(a_val)), ConstValue::Scalar(Scalar::Ptr(b_val))) => { + a_val == b_val + || match (tcx.global_alloc(a_val.alloc_id), tcx.global_alloc(b_val.alloc_id)) { + (GlobalAlloc::Function(a_instance), GlobalAlloc::Function(b_instance)) => { + a_instance == b_instance + } + _ => false, + } + } + + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { + get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) + } + + (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)); + + // Both the variant and each field have to be equal. + if a_destructured.variant == b_destructured.variant { + for (a_field, b_field) in + a_destructured.fields.iter().zip(b_destructured.fields.iter()) + { + relation.consts(a_field, b_field)?; + } + + true + } else { + false + } + } + + _ => false, + }) } impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 04ea3cbd8b6..bc15b3972c9 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -81,12 +81,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal: ty::Const { ty: const_ty, .. }, .. }), + func: Operand::Constant(box Constant { literal, .. }), args, .. } = &terminator.kind { - if let ty::FnDef(id, _) = *const_ty.kind() { + if let ty::FnDef(id, _) = *literal.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index ab7e75bf4f1..cce1549cb29 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -282,7 +282,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty); + let ty = self.sanitize_type(constant, constant.literal.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { let live_region_vid = @@ -296,7 +296,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty, + constant.literal.ty(), ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), @@ -308,13 +308,22 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.literal.ty, + constant.literal.ty(), terr, ); } } else { let tcx = self.tcx(); - if let ty::ConstKind::Unevaluated(def, substs, promoted) = constant.literal.val { + let maybe_uneval = match constant.literal { + ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(def, substs, promoted) => { + Some((def, substs, promoted)) + } + _ => None, + }, + _ => None, + }; + if let Some((def, substs, promoted)) = maybe_uneval { if let Some(promoted) = promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, promoted: &Body<'tcx>, @@ -349,7 +358,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { location.to_locations(), ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.literal.ty, + constant.literal.ty(), def.did, UserSubsts { substs, user_self_ty: None }, )), @@ -367,7 +376,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let unnormalized_ty = tcx.type_of(static_def_id); let locations = location.to_locations(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty.builtin_deref(true).unwrap().ty; + let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; if let Err(terr) = self.cx.eq_types( normalized_ty, @@ -379,7 +388,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, substs) = *constant.literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( instantiated_predicates, diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index a4e1cd2faa3..77531ae2c5f 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -3,12 +3,15 @@ use std::convert::TryFrom; use rustc_hir::Mutability; -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 crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar, }; mod error; @@ -35,6 +38,100 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(loc_place.ptr) } +/// 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> { + 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) +} + +fn const_to_valtree_inner<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, +) -> Option> { + let branches = |n, variant| { + 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())))); + let fields = (0..n).map(|i| { + let field = ecx.mplace_field(&place, i).unwrap(); + const_to_valtree_inner(ecx, &field) + }); + // For enums, we preped 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::>>()?), + )) + }; + 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(..) => unimplemented!("need to use deref_const"), + + // 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::Slice(_) | ty::Str => { + unimplemented!("need to find the backing data of the slice/str and recurse on that") + } + ty::Tuple(substs) => branches(substs.len(), None), + ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), 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(def.variants[variant].fields.len(), 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 uses `unwrap` copiously, because an already validated constant /// must have valid fields and can thus never fail outside of compiler bugs. However, it is /// invoked from the pretty printer, where it can receive enums with no variants and e.g. diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6b796eb3721..149a9f81ea0 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -689,7 +689,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let span = const_.span; let const_ = self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal); - self.const_to_op(const_, None).map_err(|err| { + self.mir_const_to_op(&const_, None).map_err(|err| { // If there was an error, set the span of the current frame to this constant. // Avoiding doing this when evaluation succeeds. self.frame_mut().loc = Err(span); diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 2c4aba19e4a..28933493a21 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -532,7 +532,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all // checked yet. // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. - self.const_to_op(val, layout)? + + self.mir_const_to_op(&val, layout)? } }; trace!("{:?}: {:?}", mir_op, *op); @@ -556,28 +557,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val: &ty::Const<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val.val { + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), + ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), + ty::ConstKind::Unevaluated(def, substs, promoted) => { + let instance = self.resolve(def, substs)?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()) + } + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { + span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) + } + ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout), + } + } + + crate fn mir_const_to_op( + &self, + val: &mir::ConstantKind<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val { + mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, None), + } + } + + crate fn const_val_to_op( + &self, + val_val: ConstValue<'tcx>, + ty: Ty<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Other cases need layout. let tag_scalar = |scalar| -> InterpResult<'tcx, _> { Ok(match scalar { Scalar::Ptr(ptr) => Scalar::Ptr(self.global_base_pointer(ptr)?), Scalar::Int(int) => Scalar::Int(int), }) }; - // Early-return cases. - let val_val = match val.val { - ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), - ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), - ty::ConstKind::Unevaluated(def, substs, promoted) => { - let instance = self.resolve(def, substs)?; - return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); - } - ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { - span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) - } - ty::ConstKind::Value(val_val) => val_val, - }; - // Other cases need layout. - let layout = - from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?; + let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.create_memory_alloc(alloc); diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 7ba79e6f759..699b531f501 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -531,7 +531,7 @@ where base.offset(from_offset, meta, layout, self) } - pub(super) fn mplace_downcast( + pub(crate) fn mplace_downcast( &self, base: &MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 93c17057590..194bc74c0fb 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -63,6 +63,10 @@ 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.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) diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 20cb989196a..911224d8c1f 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -684,7 +684,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { for op in operands { match *op { mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty); + let fn_ty = self.monomorphize(value.literal.ty()); visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); } mir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index 0dbd7ce7f1d..796d024771d 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -421,7 +421,7 @@ impl CloneShimBuilder<'tcx> { let func = Operand::Constant(box Constant { span: self.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, func_ty), + literal: ty::Const::zero_sized(tcx, func_ty).into(), }); let ref_loc = self.make_place( @@ -478,7 +478,7 @@ impl CloneShimBuilder<'tcx> { box Constant { span: self.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx, value), + literal: ty::Const::from_usize(self.tcx, value).into(), } } @@ -509,7 +509,7 @@ impl CloneShimBuilder<'tcx> { Rvalue::Use(Operand::Constant(box Constant { span: self.span, user_ty: None, - literal: len, + literal: len.into(), })), ))), ]; @@ -768,7 +768,7 @@ fn build_call_shim<'tcx>( Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: ty::Const::zero_sized(tcx, ty).into(), }), rcvr.into_iter().collect::>(), ) diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index 13d7166b4b5..748f65cba22 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -246,25 +246,27 @@ where }; // Check the qualifs of the value of `const` items. - if let ty::ConstKind::Unevaluated(def, _, promoted) = constant.literal.val { - assert!(promoted.is_none()); - // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def.did).is_none() { - let qualifs = if let Some((did, param_did)) = def.as_const_arg() { - cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) - } else { - cx.tcx.at(constant.span).mir_const_qualif(def.did) - }; + if let Some(ct) = constant.literal.const_for_ty() { + if let ty::ConstKind::Unevaluated(def, _, promoted) = ct.val { + assert!(promoted.is_none()); + // Don't peek inside trait associated constants. + if cx.tcx.trait_of_item(def.did).is_none() { + let qualifs = if let Some((did, param_did)) = def.as_const_arg() { + cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) + } else { + cx.tcx.at(constant.span).mir_const_qualif(def.did) + }; - if !Q::in_qualifs(&qualifs) { - return false; + if !Q::in_qualifs(&qualifs) { + return false; + } + + // Just in case the type is more specific than + // the definition, e.g., impl associated const + // with type parameters, take it into account. } - - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. } } // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.literal.ty) + Q::in_any_value_of_ty(cx, constant.literal.ty()) } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 9d03b1b027e..cc8669d9705 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -13,9 +13,9 @@ use rustc_middle::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc_middle::mir::{ - AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, Local, LocalDecl, LocalKind, - Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, - StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, ConstantKind, Local, LocalDecl, + LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, + Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -482,18 +482,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - match self.ecx.const_to_op(c.literal, None) { + match self.ecx.mir_const_to_op(&c.literal, None) { Ok(op) => Some(op), Err(error) => { let tcx = self.ecx.tcx.at(c.span); let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { - let lint_only = match c.literal.val { - // Promoteds must lint and not error as the user didn't ask for them - ConstKind::Unevaluated(_, _, Some(_)) => true, - // Out of backwards compatibility we cannot report hard errors in unused - // generic functions using associated constants of the generic parameters. - _ => c.literal.needs_subst(), + let lint_only = match c.literal { + ConstantKind::Ty(ct) => match ct.val { + // Promoteds must lint and not error as the user didn't ask for them + ConstKind::Unevaluated(_, _, Some(_)) => true, + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + _ => c.literal.needs_subst(), + }, + ConstantKind::Val(_, ty) => ty.needs_subst(), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -803,7 +806,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ty::Const::from_scalar(self.tcx, scalar, ty), + literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(), })) } @@ -814,9 +817,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) { if let Rvalue::Use(Operand::Constant(c)) = rval { - if !matches!(c.literal.val, ConstKind::Unevaluated(..)) { - trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); - return; + match c.literal { + ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} + _ => { + trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + return; + } } } @@ -883,13 +889,17 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { span: source_info.span, user_ty: None, - literal: self.ecx.tcx.mk_const(ty::Const { - ty, - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc, - offset: Size::ZERO, - }), - }), + literal: self + .ecx + .tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Value(ConstValue::ByRef { + alloc, + offset: Size::ZERO, + }), + }) + .into(), }))); } } diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs index 3d435f6d0e7..c0fcfb620ff 100644 --- a/compiler/rustc_mir/src/transform/elaborate_drops.rs +++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs @@ -471,7 +471,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ty::Const::from_bool(self.tcx, val), + literal: ty::Const::from_bool(self.tcx, val).into(), }))) } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index f299b6ecc28..c85e9b9b932 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -989,7 +989,7 @@ fn insert_panic_block<'tcx>( cond: Operand::Constant(box Constant { span: body.span, user_ty: None, - literal: ty::Const::from_bool(tcx, false), + literal: ty::Const::from_bool(tcx, false).into(), }), expected: true, msg: message, diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index cf85503b3d5..dd06daecd5d 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -416,7 +416,7 @@ impl Inliner<'tcx> { TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { if let ty::FnDef(def_id, substs) = - *callsite.callee.subst_mir(self.tcx, &f.literal.ty).kind() + *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() { let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); if let Ok(Some(instance)) = @@ -637,8 +637,11 @@ impl Inliner<'tcx> { // `required_consts`, here we may not only have `ConstKind::Unevaluated` // because we are calling `subst_and_normalize_erasing_regions`. caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&constant| { - matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _)) + callee_body.required_consts.iter().copied().filter(|&ct| { + match ct.literal.const_for_ty() { + Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_, _, _)), + None => true, + } }), ); } diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index bad82fe893e..7aaf0224164 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -79,7 +79,7 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { fn try_eval_bool(&self, a: &Operand<'_>) -> Option { let a = a.constant()?; - if a.literal.ty.is_bool() { a.literal.val.try_to_bool() } else { None } + if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } } /// Transform "&(*a)" ==> "a". @@ -110,12 +110,13 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Len(ref place) = *rvalue { let place_ty = place.ty(self.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.kind() { + if let ty::Array(_, len) = *place_ty.kind() { if !self.should_combine(source_info, rvalue) { return; } - let constant = Constant { span: source_info.span, literal: len, user_ty: None }; + let constant = + Constant { span: source_info.span, literal: len.into(), user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(box constant)); } } diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs index d6a73360616..e6ee474285e 100644 --- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs +++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs @@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { Rvalue::Use(Operand::Constant(box Constant { span: terminator.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit), + literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), })), )), }); diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 15c2c3a160f..d04a7011ab0 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -93,8 +93,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s - && f_c.literal.ty.is_bool() - && s_c.literal.ty.is_bool() + && f_c.literal.ty().is_bool() + && s_c.literal.ty().is_bool() && f_c.literal.try_eval_bool(tcx, param_env).is_some() && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index f60570483ce..7db790cf32b 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let unit = Rvalue::Use(Operand::Constant(box Constant { span: statement.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit), + literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(), })); mem::replace(rhs, unit) }, @@ -998,20 +998,22 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: tcx.mk_const(ty::Const { - ty, - val: ty::ConstKind::Unevaluated( - def, - InternalSubsts::for_item(tcx, def.did, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), - Some(promoted_id), - ), - }), + literal: tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Unevaluated( + def, + InternalSubsts::for_item(tcx, def.did, |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }), + Some(promoted_id), + ), + }) + .into(), })) }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); @@ -1250,8 +1252,8 @@ crate fn is_const_fn_in_array_repeat_expression<'tcx>( if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = *ty.kind() { + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, _) = *literal.ty().kind() { if let Some((destination_place, _)) = destination { if destination_place == place { if is_const_fn(ccx.tcx, def_id) { diff --git a/compiler/rustc_mir/src/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs index a63ab30a68f..2b518bd3a48 100644 --- a/compiler/rustc_mir/src/transform/required_consts.rs +++ b/compiler/rustc_mir/src/transform/required_consts.rs @@ -14,10 +14,10 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { - let const_kind = constant.literal.val; - - if let ConstKind::Unevaluated(_, _, _) = const_kind { - self.required_consts.push(*constant); + if let Some(ct) = constant.literal.const_for_ty() { + if let ConstKind::Unevaluated(_, _, _) = ct.val { + self.required_consts.push(*constant); + } } } } diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs index 7598be4e4a1..a6b8f20f6d4 100644 --- a/compiler/rustc_mir/src/transform/rustc_peek.rs +++ b/compiler/rustc_mir/src/transform/rustc_peek.rs @@ -205,7 +205,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, substs) = *func.literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { let sig = tcx.fn_sig(def_id); let name = tcx.item_name(def_id); if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 32df40ebf9e..9f473f3bae5 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -205,12 +205,12 @@ fn find_branch_value_info<'tcx>( match (left, right) { (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { - let branch_value_ty = branch_value.literal.ty; + let branch_value_ty = branch_value.literal.ty(); // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { return None; }; - let branch_value_scalar = branch_value.literal.val.try_to_scalar()?; + let branch_value_scalar = branch_value.literal.try_to_scalar()?; Some((branch_value_scalar, branch_value_ty, *to_switch_on)) } _ => None, diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs index b22dadcd7d2..e9190d7ebef 100644 --- a/compiler/rustc_mir/src/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -1035,7 +1035,7 @@ where Operand::Constant(box Constant { span: self.source_info.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx(), val.into()), + literal: ty::Const::from_usize(self.tcx(), val.into()).into(), }) } diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs index 5b146eeb87c..ddda98d1616 100644 --- a/compiler/rustc_mir/src/util/find_self_call.rs +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator { debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, substs) = *ty.kind() { + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 247a0beccaf..1bf010ffca7 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -439,7 +439,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); let Constant { span, user_ty, literal } = constant; - match literal.ty.kind() { + match literal.ty().kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -449,7 +449,12 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {:?}", user_ty)); } - self.push(&format!("+ literal: {:?}", literal)); + match literal { + ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), + ConstantKind::Val(val, ty) => { + self.push(&format!("+ literal: {:?}, {}", val, ty)) + } + } } } } diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index 42e2b242d77..e562e52f841 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -68,7 +68,7 @@ impl<'tcx> CFG<'tcx> { Rvalue::Use(Operand::Constant(box Constant { span: source_info.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit), + literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), })), ); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 727aedb0ef8..57f56e2d092 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -11,7 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> { let this = self; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; - match kind { + match *kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { @@ -22,11 +22,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) }); assert_eq!(literal.ty, ty); - Constant { span, user_ty, literal } + Constant { span, user_ty, literal: literal.into() } + } + ExprKind::StaticRef { literal, .. } => { + Constant { span, user_ty: None, literal: literal.into() } } - ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, ExprKind::ConstBlock { value } => { - Constant { span: span, user_ty: None, literal: value } + Constant { span: span, user_ty: None, literal: value.into() } } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index ce816b6229e..7f24a41b00b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -255,7 +255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Constant(box Constant { span: expr_span, user_ty: None, - literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit), + literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(), }))) } ExprKind::Yield { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a2adbdddc40..fc92e8019c2 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: expr_span, user_ty: None, - literal: ty::Const::from_bool(this.tcx, true), + literal: ty::Const::from_bool(this.tcx, true).into(), }, ); @@ -157,7 +157,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: expr_span, user_ty: None, - literal: ty::Const::from_bool(this.tcx, false), + literal: ty::Const::from_bool(this.tcx, false).into(), }, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 6820d4ba35a..b082169cd63 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Need to experiment. user_ty: None, - literal: method, + literal: method.into(), }), args: vec![val, expect], destination: Some((eq_result, eq_block)), diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 62c217a12aa..a1126d1c3d5 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -30,6 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, literal: &'tcx ty::Const<'tcx>, ) -> Operand<'tcx> { + let literal = literal.into(); let constant = box Constant { span, user_ty: None, literal }; Operand::Constant(constant) } @@ -57,7 +58,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: source_info.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx, value), + literal: ty::Const::from_usize(self.tcx, value).into(), }, ); temp diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index fe8a58c0088..c0433604f8c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -68,11 +68,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { // FIXME(#31407) this is only necessary because float parsing is buggy self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)"); // create a dummy value and continue compiling - Const::from_bits(self.tcx, 0, self.param_env.and(ty)) + self.tcx.const_error(ty) } Err(LitToConstError::Reported) => { // create a dummy value and continue compiling - Const::from_bits(self.tcx, 0, self.param_env.and(ty)) + self.tcx.const_error(ty) } Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"), } diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1ae5bf12cab..e467f419863 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -228,6 +228,15 @@ impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { } } +impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for ty::PolyTraitRef<'tcx> { fn query_crate(&self) -> CrateNum { self.def_id().krate diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f4983dd7531..670527fb3f0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -377,7 +377,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let local = self.place_to_local(span, p)?; Ok(self.locals[local]) } - mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)), + mir::Operand::Constant(ct) => match ct.literal { + mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), + mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, + }, } }