diff options
| author | b-naber <bn263@gmx.de> | 2022-02-16 10:56:01 +0100 |
|---|---|---|
| committer | b-naber <bn263@gmx.de> | 2022-06-14 16:07:11 +0200 |
| commit | 705d818bd52a6324d5e7693cc4306457395eebc8 (patch) | |
| tree | f5363e1a8b0426bc961970028c23670869e344fb /compiler | |
| parent | edab34ab2abbafc16a78daedf71dbacd2eb0b7bf (diff) | |
| download | rust-705d818bd52a6324d5e7693cc4306457395eebc8.tar.gz rust-705d818bd52a6324d5e7693cc4306457395eebc8.zip | |
implement valtrees as the type-system representation for constant values
Diffstat (limited to 'compiler')
52 files changed, 1082 insertions, 642 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3d14a0eca52..ef72e6efb94 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -127,7 +127,7 @@ pub(crate) fn codegen_constant<'tcx>( ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), }; let const_val = match const_.kind() { - ConstKind::Value(const_val) => const_val, + ConstKind::Value(valtree) => fx.tcx.valtree_to_const_val((const_.ty(), valtree)), ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) if fx.tcx.is_static(def.did) => { @@ -468,9 +468,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( ) -> Option<ConstValue<'tcx>> { match operand { Operand::Constant(const_) => match const_.literal { - ConstantKind::Ty(const_) => { - fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).kind().try_to_value() - } + ConstantKind::Ty(const_) => fx + .monomorphize(const_) + .eval_for_mir(fx.tcx, ParamEnv::reveal_all()) + .try_to_value(fx.tcx), ConstantKind::Val(val, _) => Some(val), }, // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 7e0d3f9adaa..9a995fbf65c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); err }), - ty::ConstKind::Value(value) => Ok(value), + ty::ConstKind::Value(val) => Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val))), err => span_bug!( constant.span, "encountered bad ConstKind after monomorphizing: {:?}", @@ -58,14 +58,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant .map(|val| { let field_ty = ty.builtin_index().unwrap(); - let c = ty::Const::from_value(bx.tcx(), val, ty); + let c = mir::ConstantKind::from_value(val, ty); let values: Vec<_> = bx .tcx() - .destructure_const(ty::ParamEnv::reveal_all().and(c)) + .destructure_mir_constant(ty::ParamEnv::reveal_all(), c) .fields .iter() .map(|field| { - if let Some(prim) = field.kind().try_to_scalar() { + if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); let Abi::Scalar(scalar) = layout.abi else { bug!("from_const: invalid ByVal layout: {:#?}", layout); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 0c20324e452..b7e5e7aea49 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -196,7 +196,7 @@ pub(super) fn op_to_const<'tcx>( } #[instrument(skip(tcx), level = "debug")] -fn turn_into_const_value<'tcx>( +pub(crate) fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, @@ -222,6 +222,7 @@ fn turn_into_const_value<'tcx>( const_val } +#[instrument(skip(tcx), level = "debug")] pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, @@ -256,6 +257,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } +#[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6ee77db4017..51edf64de80 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,12 +1,11 @@ // Not in interpret to make sure we do not use private implementation details -use std::convert::TryFrom; - use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; +use rustc_target::abi::VariantIdx; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, @@ -25,6 +24,12 @@ pub use fn_queries::*; pub use machine::*; pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value}; +pub(crate) enum ValTreeCreationError { + NonSupportedType, + Other, +} +pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>; + pub(crate) fn const_caller_location( tcx: TyCtxt<'_>, (file, line, col): (Symbol, u32, u32), @@ -39,16 +44,6 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx)) } -// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. -const VALTREE_MAX_NODES: usize = 1000; - -pub(crate) enum ValTreeCreationError { - NodesOverflow, - NonSupportedType, - Other, -} -pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>; - /// Evaluates a constant and turns it into a type-level constant value. pub(crate) fn eval_to_valtree<'tcx>( tcx: TyCtxt<'tcx>, @@ -56,6 +51,8 @@ pub(crate) fn eval_to_valtree<'tcx>( cid: GlobalId<'tcx>, ) -> EvalToValTreeResult<'tcx> { let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; + + // FIXME Need to provide a span to `eval_to_valtree` let ecx = mk_eval_cx( tcx, DUMMY_SP, param_env, // It is absolutely crucial for soundness that @@ -65,65 +62,89 @@ pub(crate) fn eval_to_valtree<'tcx>( let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); debug!(?place); - let mut num_nodes = 0; - let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); + let valtree_result = const_to_valtree_inner(&ecx, &place); match valtree_result { Ok(valtree) => Ok(Some(valtree)), - Err(err) => { - let did = cid.instance.def_id(); - let s = cid.display(tcx); - match err { - ValTreeCreationError::NodesOverflow => { - let msg = format!("maximum number of nodes exceeded in constant {}", &s); - let mut diag = match tcx.hir().span_if_local(did) { - Some(span) => tcx.sess.struct_span_err(span, &msg), - None => tcx.sess.struct_err(&msg), - }; - diag.emit(); - - Ok(None) - } - ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None), - } - } + Err(_) => Ok(None), } } -/// This function should never fail for validated constants. However, it is also invoked from the -/// pretty printer which might attempt to format invalid constants and in that case it might fail. +/// Tries to destructure constants of type Array or Adt into the constants +/// of its fields. pub(crate) fn try_destructure_const<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: ty::Const<'tcx>, -) -> InterpResult<'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)?; - // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty().kind() { - ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), - // Checks if we have any variants, to avoid downcasting to a non-existing variant (when - // there are no variants `read_discriminant` successfully returns a non-existing variant - // index). - ty::Adt(def, _) if def.variants().is_empty() => throw_ub!(Unreachable), - ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op)?.1; - let down = ecx.operand_downcast(&op, variant)?; - (def.variant(variant).fields.len(), Some(variant), down) - } - ty::Tuple(substs) => (substs.len(), None, op), - _ => bug!("cannot destructure constant {:?}", val), - }; - let fields = (0..field_count) - .map(|i| { - let field_op = ecx.operand_field(&down, i)?; - let val = op_to_const(&ecx, &field_op); - Ok(ty::Const::from_value(tcx, val, field_op.layout.ty)) - }) - .collect::<InterpResult<'tcx, Vec<_>>>()?; - let fields = tcx.arena.alloc_from_iter(fields); - Ok(mir::DestructuredConst { variant, fields }) + const_: ty::Const<'tcx>, +) -> Option<mir::DestructuredConst<'tcx>> { + if let ty::ConstKind::Value(valtree) = const_.val() { + let branches = match valtree { + ty::ValTree::Branch(b) => b, + _ => return None, + }; + + let (fields, variant) = match const_.ty().kind() { + ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { + // construct the consts for the elements of the array/slice + let field_consts = branches + .iter() + .map(|b| { + tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }) + }) + .collect::<Vec<_>>(); + debug!(?field_consts); + + (field_consts, None) + } + ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"), + ty::Adt(def, substs) => { + let variant_idx = if def.is_enum() { + VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?) + } else { + VariantIdx::from_u32(0) + }; + let fields = &def.variant(variant_idx).fields; + let mut field_consts = Vec::with_capacity(fields.len()); + + // Note: First element inValTree corresponds to variant of enum + let mut valtree_idx = if def.is_enum() { 1 } else { 0 }; + for field in fields { + let field_ty = field.ty(tcx, substs); + let field_valtree = branches[valtree_idx]; // first element of branches is variant + let field_const = tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Value(field_valtree), + ty: field_ty, + }); + field_consts.push(field_const); + valtree_idx += 1; + } + debug!(?field_consts); + + (field_consts, Some(variant_idx)) + } + ty::Tuple(elem_tys) => { + let fields = elem_tys + .iter() + .enumerate() + .map(|(i, elem_ty)| { + let elem_valtree = branches[i]; + tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Value(elem_valtree), + ty: elem_ty, + }) + }) + .collect::<Vec<_>>(); + + (fields, None) + } + _ => bug!("cannot destructure constant {:?}", const_), + }; + + let fields = tcx.arena.alloc_from_iter(fields.into_iter()); + + Some(mir::DestructuredConst { variant, fields }) + } else { + None + } } #[instrument(skip(tcx), level = "debug")] @@ -143,8 +164,8 @@ pub(crate) fn try_destructure_mir_constant<'tcx>( throw_ub!(Unreachable) } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).unwrap().1; - let down = ecx.operand_downcast(&op, variant).unwrap(); + let variant = ecx.read_discriminant(&op)?.1; + let down = ecx.operand_downcast(&op, variant)?; (def.variants()[variant].fields.len(), Some(variant), down) } ty::Tuple(substs) => (substs.len(), None, op), @@ -164,43 +185,6 @@ pub(crate) fn try_destructure_mir_constant<'tcx>( } #[instrument(skip(tcx), level = "debug")] -pub(crate) fn deref_const<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: ty::Const<'tcx>, -) -> ty::Const<'tcx> { - trace!("deref_const: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); - let mplace = ecx.deref_operand(&op).unwrap(); - if let Some(alloc_id) = mplace.ptr.provenance { - assert_eq!( - tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability, - Mutability::Not, - "deref_const cannot be used with mutable allocations as \ - that could allow pattern matching to observe mutable statics", - ); - } - - let ty = match mplace.meta { - MemPlaceMeta::None => mplace.layout.ty, - MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), - // In case of unsized types, figure out the real type behind. - MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { - ty::Str => bug!("there's no sized equivalent of a `str`"), - ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()), - _ => bug!( - "type {} should not have metadata, but had {:?}", - mplace.layout.ty, - mplace.meta - ), - }, - }; - - tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) -} - -#[instrument(skip(tcx), level = "debug")] pub(crate) fn deref_mir_constant<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -211,16 +195,16 @@ pub(crate) fn deref_mir_constant<'tcx>( let mplace = ecx.deref_operand(&op).unwrap(); if let Some(alloc_id) = mplace.ptr.provenance { assert_eq!( - tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability, + tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0 .0.mutability, Mutability::Not, - "deref_const cannot be used with mutable allocations as \ + "deref_mir_constant cannot be used with mutable allocations as \ that could allow pattern matching to observe mutable statics", ); } let ty = match mplace.meta { MemPlaceMeta::None => mplace.layout.ty, - MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + MemPlaceMeta::Poison => bug!("poison metadata in `deref_mir_constant`: {:#?}", mplace), // In case of unsized types, figure out the real type behind. MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { ty::Str => bug!("there's no sized equivalent of a `str`"), diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 7346d69bb5d..080133275a6 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,24 +1,21 @@ use super::eval_queries::{mk_eval_cx, op_to_const}; use super::machine::CompileTimeEvalContext; -use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; +use super::{ValTreeCreationError, ValTreeCreationResult}; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit, }; +use crate::interpret::{MPlaceTy, Value}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_target::abi::{Align, VariantIdx}; -use crate::interpret::MPlaceTy; -use crate::interpret::Value; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; - #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, n: usize, variant: Option<VariantIdx>, - num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { let place = match variant { Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), @@ -30,7 +27,7 @@ fn branches<'tcx>( let mut fields = Vec::with_capacity(n); for i in 0..n { let field = ecx.mplace_field(&place, i).unwrap(); - let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; + let valtree = const_to_valtree_inner(ecx, &field)?; fields.push(Some(valtree)); } @@ -42,11 +39,6 @@ fn branches<'tcx>( .collect::<Option<Vec<_>>>() .expect("should have already checked for errors in ValTree creation"); - // Have to account for ZSTs here - if branches.len() == 0 { - *num_nodes += 1; - } - Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches))) } @@ -54,7 +46,6 @@ fn branches<'tcx>( fn slice_branches<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, - num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { let n = place .len(&ecx.tcx.tcx) @@ -63,7 +54,7 @@ fn slice_branches<'tcx>( let mut elems = Vec::with_capacity(n as usize); for i in 0..n { let place_elem = ecx.mplace_index(place, i).unwrap(); - let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; + let valtree = const_to_valtree_inner(ecx, &place_elem)?; elems.push(valtree); } @@ -74,18 +65,12 @@ fn slice_branches<'tcx>( pub(crate) fn const_to_valtree_inner<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, - num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { - if *num_nodes >= VALTREE_MAX_NODES { - return Err(ValTreeCreationError::NodesOverflow); - } - let ty = place.layout.ty; debug!("ty kind: {:?}", ty.kind()); match ty.kind() { ty::FnDef(..) => { - *num_nodes += 1; Ok(ty::ValTree::zst()) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { @@ -93,7 +78,6 @@ pub(crate) fn const_to_valtree_inner<'tcx>( return Err(ValTreeCreationError::Other); }; let val = val.to_scalar().unwrap(); - *num_nodes += 1; Ok(ty::ValTree::Leaf(val.assert_int())) } @@ -110,11 +94,11 @@ pub(crate) fn const_to_valtree_inner<'tcx>( }; debug!(?derefd_place); - const_to_valtree_inner(ecx, &derefd_place, num_nodes) + const_to_valtree_inner(ecx, &derefd_place) } ty::Str | ty::Slice(_) | ty::Array(_, _) => { - slice_branches(ecx, place, num_nodes) + slice_branches(ecx, place) } // 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 @@ -123,7 +107,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType), ty::Tuple(elem_tys) => { - branches(ecx, place, elem_tys.len(), None, num_nodes) + branches(ecx, place, elem_tys.len(), None) } ty::Adt(def, _) => { @@ -136,7 +120,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else { return Err(ValTreeCreationError::Other); }; - branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) + branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant)) } ty::Never @@ -234,13 +218,9 @@ fn create_pointee_place<'tcx>( // Get the size of the memory behind the DST let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap(); - let ptr = ecx - .allocate_ptr( - size_of_sized_part.checked_add(dst_size, &tcx).unwrap(), - Align::from_bytes(1).unwrap(), - MemoryKind::Stack, - ) - .unwrap(); + let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap(); + let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap(); + let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap(); debug!(?ptr); let place = MPlaceTy::from_aligned_ptr_with_meta( @@ -262,7 +242,7 @@ fn create_pointee_place<'tcx>( #[instrument(skip(tcx), level = "debug")] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, + param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, valtree: ty::ValTree<'tcx>, ) -> ConstValue<'tcx> { // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s @@ -272,8 +252,8 @@ pub fn valtree_to_const_value<'tcx>( // create inner `MPlace`s which are filled recursively. // FIXME Does this need an example? - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::empty(), false); - let param_env_ty = ty::ParamEnv::empty().and(ty); + let (param_env, ty) = param_env_ty.into_parts(); + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); match ty.kind() { ty::FnDef(..) => { @@ -336,7 +316,6 @@ pub fn valtree_to_const_value<'tcx>( } } -// FIXME Needs a better/correct name #[instrument(skip(ecx), level = "debug")] fn valtree_into_mplace<'tcx>( ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 597ca4cfcdd..e9a9c0e1713 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -637,7 +637,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c) } - ty::ConstKind::Value(val) => self.const_val_to_op(val, c.ty(), layout), + ty::ConstKind::Value(valtree) => { + let ty = val.ty(); + let const_val = self.tcx.valtree_to_const_val((ty, valtree)); + self.const_val_to_op(const_val, ty, layout) + } } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 04410ca3828..64a74e9d7e2 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -34,6 +34,7 @@ pub mod interpret; pub mod transform; pub mod util; +use rustc_middle::ty; use rustc_middle::ty::query::Providers; pub fn provide(providers: &mut Providers) { @@ -41,10 +42,7 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.try_destructure_const = |tcx, param_env_and_val| { - let (param_env, c) = param_env_and_val.into_parts(); - const_eval::try_destructure_const(tcx, param_env, c).ok() - }; + providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val); providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); const_eval::eval_to_valtree(tcx, param_env, raw) @@ -53,11 +51,8 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::try_destructure_mir_constant(tcx, param_env, value).ok() }; - providers.valtree_to_const_val = - |tcx, (ty, valtree)| const_eval::valtree_to_const_value(tcx, ty, valtree); - 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) + providers.valtree_to_const_val = |tcx, (ty, valtree)| { + const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree) }; providers.deref_mir_constant = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 67a356918d1..3595a488d0c 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -765,7 +765,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let unit = Rvalue::Use(Operand::Constant(Box::new(Constant { span: statement.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(), + literal: ConstantKind::zero_sized(self.tcx.types.unit), }))); mem::replace(rhs, unit) }, @@ -835,26 +835,25 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); + let _const = tcx.mk_const(ty::ConstS { + ty, + kind: ty::ConstKind::Unevaluated(ty::Unevaluated { + def, + substs: 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) + } + }), + promoted: Some(promoted_id), + }), + }); Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: tcx - .mk_const(ty::ConstS { - ty, - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs: 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) - } - }), - promoted: Some(promoted_id), - }), - }) - .into(), + literal: ConstantKind::from_const(_const, tcx), })) }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 59c708fb750..93a067cb516 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -20,7 +20,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToConstValueResult}; +use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -1616,6 +1616,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { u } + pub fn try_const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + unevaluated: ty::Unevaluated<'tcx>, + ty: Ty<'tcx>, + span: Option<Span>, + ) -> Result<ty::Const<'tcx>, ErrorHandled> { + match self.const_eval_resolve(param_env, unevaluated, span) { + Ok(Some(val)) => Ok(ty::Const::from_value(self.tcx, val, ty)), + Ok(None) => { + let tcx = self.tcx; + let def_id = unevaluated.def.did; + span_bug!( + tcx.def_span(def_id), + "unable to construct a constant value for the unevaluated constant {:?}", + unevaluated + ); + } + Err(err) => Err(err), + } + } + /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given @@ -1634,7 +1656,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, unevaluated: ty::Unevaluated<'tcx>, span: Option<Span>, - ) -> EvalToConstValueResult<'tcx> { + ) -> EvalToValTreeResult<'tcx> { let substs = self.resolve_vars_if_possible(unevaluated.substs); debug!(?substs); @@ -1658,7 +1680,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. - self.tcx.const_eval_resolve(param_env_erased, unevaluated, span) + self.tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } /// `ty_or_const_infer_var_changed` is equivalent to one of these two: diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 8fc957cf49c..69353232f06 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,4 @@ -use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; +use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; use crate::ty::fold::TypeFoldable; @@ -11,6 +11,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + /// + /// Note: Returns a `ConstValue`, which isn't supposed to be used in the type system. In order to + /// evaluate to a type-system level constant value use `const_eval_poly_for_typeck`. + #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { // In some situations def_id will have substitutions within scope, but they aren't allowed // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions @@ -23,6 +27,22 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, cid, None) } + /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts + /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_poly_for_typeck(self, def_id: DefId) -> EvalToValTreeResult<'tcx> { + // In some situations def_id will have substitutions within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions + // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are + // encountered. + let substs = InternalSubsts::identity_for_item(self, def_id); + let instance = ty::Instance::new(def_id, substs); + let cid = GlobalId { instance, promoted: None }; + let param_env = self.param_env(def_id).with_reveal_all_normalized(self); + self.const_eval_global_id_for_typeck(param_env, cid, None) + } + /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given @@ -59,6 +79,33 @@ impl<'tcx> TyCtxt<'tcx> { } } + #[instrument(level = "debug", skip(self))] + pub fn const_eval_resolve_for_typeck( + self, + param_env: ty::ParamEnv<'tcx>, + ct: ty::Unevaluated<'tcx>, + span: Option<Span>, + ) -> EvalToValTreeResult<'tcx> { + // Cannot resolve `Unevaluated` constants that contain inference + // variables. We reject those here since `resolve_opt_const_arg` + // would fail otherwise. + // + // When trying to evaluate constants containing inference variables, + // use `Infcx::const_eval_resolve` instead. + if ct.substs.has_infer_types_or_consts() { + bug!("did not expect inference variables here"); + } + + match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + Ok(Some(instance)) => { + let cid = GlobalId { instance, promoted: ct.promoted }; + self.const_eval_global_id_for_typeck(param_env, cid, span) + } + Ok(None) => Err(ErrorHandled::TooGeneric), + Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + } + } + pub fn const_eval_instance( self, param_env: ty::ParamEnv<'tcx>, @@ -68,7 +115,8 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) } - /// Evaluate a constant. + /// Evaluate a constant to a `ConstValue`. + #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id( self, param_env: ty::ParamEnv<'tcx>, @@ -86,6 +134,27 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Evaluate a constant to a type-level constant. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_global_id_for_typeck( + self, + param_env: ty::ParamEnv<'tcx>, + cid: GlobalId<'tcx>, + span: Option<Span>, + ) -> EvalToValTreeResult<'tcx> { + let param_env = param_env.with_const(); + debug!(?param_env); + // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should + // improve caching of queries. + let inputs = self.erase_regions(param_env.and(cid)); + debug!(?inputs); + if let Some(span) = span { + self.at(span).eval_to_valtree(inputs) + } else { + self.eval_to_valtree(inputs) + } + } + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. #[inline(always)] pub fn eval_static_initializer( @@ -125,11 +194,8 @@ impl<'tcx> TyCtxtAt<'tcx> { impl<'tcx> TyCtxt<'tcx> { /// Destructure a type-level constant ADT or array into its variant index and its field values. /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. - pub fn destructure_const( - self, - param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>, - ) -> mir::DestructuredConst<'tcx> { - self.try_destructure_const(param_env_and_val).unwrap() + pub fn destructure_const(self, const_: ty::Const<'tcx>) -> mir::DestructuredConst<'tcx> { + self.try_destructure_const(const_).unwrap() } /// Destructure a mir constant ADT or array into its variant index and its field values. diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 146ae45e468..f566467b7ce 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -78,6 +78,7 @@ impl<'tcx> ConstValue<'tcx> { Some(self.try_to_scalar()?.assert_int()) } + #[inline(always)] pub fn try_to_bits(&self, size: Size) -> Option<u128> { self.try_to_scalar_int()?.to_bits(size).ok() } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1511b51fa25..512615ccbab 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,9 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::coverage::{CodeRegion, CoverageKind}; -use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar}; +use crate::mir::interpret::{ + AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar, +}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -1444,7 +1446,11 @@ impl<'tcx> BasicBlockData<'tcx> { } pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { &self.statements[index] } else { &self.terminator } + if index < self.statements.len() { + &self.statements[index] + } else { + &self.terminator + } } } @@ -2465,7 +2471,11 @@ impl<'tcx> Operand<'tcx> { /// find as the `func` in a [`TerminatorKind::Call`]. pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> { let const_ty = self.constant()?.literal.ty(); - if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None } + if let ty::FnDef(def_id, substs) = *const_ty.kind() { + Some((def_id, substs)) + } else { + None + } } } @@ -2953,22 +2963,9 @@ impl<'tcx> Constant<'tcx> { } } -impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> { - #[inline] - fn from(ct: ty::Const<'tcx>) -> Self { - match ct.kind() { - ty::ConstKind::Value(cv) => { - // FIXME Once valtrees are introduced we need to convert those - // into `ConstValue` instances here - Self::Val(cv, ct.ty()) - } - _ => Self::Ty(ct), - } - } -} - impl<'tcx> ConstantKind<'tcx> { /// Returns `None` if the constant is not trivially safe for use in the type system. + #[inline] pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> { match self { ConstantKind::Ty(c) => Some(*c), @@ -2976,6 +2973,7 @@ impl<'tcx> ConstantKind<'tcx> { } } + #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { ConstantKind::Ty(c) => c.ty(), @@ -2983,10 +2981,10 @@ impl<'tcx> ConstantKind<'tcx> { } } - pub fn try_val(&self) -> Option<ConstValue<'tcx>> { + pub fn try_val(&self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> { match self { ConstantKind::Ty(c) => match c.kind() { - ty::ConstKind::Value(v) => Some(v), + ty::ConstKind::Value(v) => Some(tcx.valtree_to_const_val((c.ty(), v))), _ => None, }, ConstantKind::Val(v, _) => Some(*v), @@ -2994,21 +2992,33 @@ impl<'tcx> ConstantKind<'tcx> { } #[inline] - pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> { + pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> { match self { - ConstantKind::Ty(c) => c.kind().try_to_value(), + ConstantKind::Ty(c) => match c.kind() { + ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))), + _ => None, + }, ConstantKind::Val(val, _) => Some(val), } } #[inline] pub fn try_to_scalar(self) -> Option<Scalar> { - self.try_to_value()?.try_to_scalar() + match self { + ConstantKind::Ty(c) => match c.val() { + ty::ConstKind::Value(valtree) => match valtree { + ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)), + ty::ValTree::Branch(_) => None, + }, + _ => None, + }, + ConstantKind::Val(val, _) => val.try_to_scalar(), + } } #[inline] pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - Some(self.try_to_value()?.try_to_scalar()?.assert_int()) + Some(self.try_to_scalar()?.assert_int()) } #[inline] @@ -3025,9 +3035,7 @@ impl<'tcx> ConstantKind<'tcx> { pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { match self { Self::Ty(c) => { - // FIXME Need to use a different evaluation function that directly returns a `ConstValue` - // if evaluation succeeds and does not create a ValTree first - if let Some(val) = c.kind().try_eval(tcx, param_env) { + if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { match val { Ok(val) => Self::Val(val, c.ty()), Err(_) => Self::Ty(tcx.const_error(self.ty())), @@ -3081,6 +3089,11 @@ impl<'tcx> ConstantKind<'tcx> { } } + #[inline] + pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self { + Self::Val(val, ty) + } + pub fn from_bits( tcx: TyCtxt<'tcx>, bits: u128, @@ -3097,11 +3110,13 @@ impl<'tcx> ConstantKind<'tcx> { Self::Val(cv, param_env_ty.value) } + #[inline] pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { let cv = ConstValue::from_bool(v); Self::Val(cv, tcx.types.bool) } + #[inline] pub fn zero_sized(ty: Ty<'tcx>) -> Self { let cv = ConstValue::Scalar(Scalar::ZST); Self::Val(cv, ty) @@ -3112,6 +3127,12 @@ impl<'tcx> ConstantKind<'tcx> { Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty)) } + #[inline] + pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self { + let val = ConstValue::Scalar(s); + Self::Val(val, ty) + } + /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly /// converted to a constant, everything else becomes `Unevaluated`. pub fn from_anon_const( @@ -3199,8 +3220,10 @@ impl<'tcx> ConstantKind<'tcx> { } _ => expr, }; + debug!("expr.kind: {:?}", expr.kind); let ty = tcx.type_of(def.def_id_for_type_of()); + debug!(?ty); // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` // does not provide the parents generics to anonymous constants. We still allow generic const @@ -3224,6 +3247,7 @@ impl<'tcx> ConstantKind<'tcx> { kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)), ty, }); + debug!(?ty_const); return Self::Ty(ty_const); } @@ -3253,8 +3277,12 @@ impl<'tcx> ConstantKind<'tcx> { debug!(?span, ?param_env); match tcx.const_eval_resolve(param_env, uneval, Some(span)) { - Ok(val) => Self::Val(val, ty), + Ok(val) => { + debug!("evaluated const value: {:?}", val); + Self::Val(val, ty) + } Err(_) => { + debug!("error encountered during evaluation"); // Error was handled in `const_eval_resolve`. Here we just create a // new unevaluated const and error hard later in codegen let ty_const = tcx.mk_const(ty::ConstS { @@ -3265,11 +3293,22 @@ impl<'tcx> ConstantKind<'tcx> { }), ty, }); + debug!(?ty_const); Self::Ty(ty_const) } } } + + pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + match c.val() { + ty::ConstKind::Value(valtree) => { + let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); + Self::Val(const_val, c.ty()) + } + _ => Self::Ty(c), + } + } } /// A collection of projections into user types. @@ -3485,20 +3524,182 @@ fn pretty_print_const<'tcx>( }) } +fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result { + fmt.write_str("b\"")?; + for &c in byte_str { + for e in std::ascii::escape_default(c) { + fmt.write_char(e as char)?; + } + } + fmt.write_str("\"")?; + + Ok(()) +} + +fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result { + let mut first = true; + for elem in elems { + if !first { + fmt.write_str(", ")?; + } + fmt.write_str(&format!("{}", elem))?; + first = false; + } + Ok(()) +} + fn pretty_print_const_value<'tcx>( - val: interpret::ConstValue<'tcx>, + ct: ConstValue<'tcx>, ty: Ty<'tcx>, fmt: &mut Formatter<'_>, - print_types: bool, + print_ty: bool, ) -> fmt::Result { use crate::ty::print::PrettyPrinter; + ty::tls::with(|tcx| { - let val = tcx.lift(val).unwrap(); + let ct = tcx.lift(ct).unwrap(); let ty = tcx.lift(ty).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - let cx = cx.pretty_print_const_value(val, ty, print_types)?; - fmt.write_str(&cx.into_buffer())?; + + if tcx.sess.verbose() { + fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?; + return Ok(()); + } + + let u8_type = tcx.types.u8; + match (ct, ty.kind()) { + // Byte/string slices, printed as (byte) string literals. + (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => { + match inner.kind() { + ty::Slice(t) => { + if *t == u8_type { + // The `inspect` here is okay since we checked the bounds, and there are + // no relocations (we have an active slice reference here). We don't use + // this result to affect interpreter execution. + let byte_str = data + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(start..end); + pretty_print_byte_str(fmt, byte_str)?; + return Ok(()); + } + } + ty::Str => { + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active `str` reference here). We don't use this + // result to affect interpreter execution. + let slice = data + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(start..end); + fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?; + return Ok(()); + } + _ => {} + } + } + (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { + let n = n.val().try_to_bits(tcx.data_layout.pointer_size).unwrap(); + // cast is ok because we already checked for pointer size (32 or 64 bit) above + let range = AllocRange { start: offset, size: Size::from_bytes(n) }; + let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap(); + fmt.write_str("*")?; + pretty_print_byte_str(fmt, byte_str)?; + return Ok(()); + } + // Aggregates, printed as array/tuple/struct/variant construction syntax. + // + // NB: the `has_param_types_or_consts` check ensures that we can use + // the `destructure_const` query with an empty `ty::ParamEnv` without + // introducing ICEs (e.g. via `layout_of`) from missing bounds. + // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` + // to be able to destructure the tuple into `(0u8, *mut T) + // + // 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 ct = tcx.lift(ct).unwrap(); + let ty = tcx.lift(ty).unwrap(); + if let Some(contents) = tcx.try_destructure_mir_constant( + ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)), + ) { + let fields = contents.fields.iter().copied().collect::<Vec<_>>(); + match *ty.kind() { + ty::Array(..) => { + fmt.write_str("[")?; + comma_sep(fmt, fields)?; + fmt.write_str("]")?; + } + ty::Tuple(..) => { + fmt.write_str("(")?; + comma_sep(fmt, fields)?; + if contents.fields.len() == 1 { + fmt.write_str(",")?; + } + fmt.write_str(")")?; + } + ty::Adt(def, _) if def.variants().is_empty() => { + fmt.write_str(&format!("{{unreachable(): {}}}", ty))?; + } + ty::Adt(def, substs) => { + let variant_idx = contents + .variant + .expect("destructed mir constant of adt without variant idx"); + let variant_def = &def.variant(variant_idx); + let substs = tcx.lift(substs).unwrap(); + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let cx = cx.print_value_path(variant_def.def_id, substs)?; + fmt.write_str(&cx.into_buffer())?; + + match variant_def.ctor_kind { + CtorKind::Const => {} + CtorKind::Fn => { + fmt.write_str("(")?; + comma_sep(fmt, fields)?; + fmt.write_str(")")?; + } + CtorKind::Fictive => { + fmt.write_str(" {{ ")?; + let mut first = true; + for (field_def, field) in iter::zip(&variant_def.fields, fields) + { + if !first { + fmt.write_str(", ")?; + } + fmt.write_str(&format!("{}: {}", field_def.name, field))?; + first = false; + } + fmt.write_str(" }}")?; + } + } + } + _ => unreachable!(), + } + return Ok(()); + } else { + // Fall back to debug pretty printing for invalid constants. + fmt.write_str(&format!("{:?}", ct))?; + if print_ty { + fmt.write_str(&format!(": {}", ty))?; + } + return Ok(()); + }; + } + (ConstValue::Scalar(scalar), _) => { + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let ty = tcx.lift(ty).unwrap(); + cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?; + fmt.write_str(&cx.into_buffer())?; + return Ok(()); + } + // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading + // their fields instead of just dumping the memory. + _ => {} + } + // fallback + fmt.write_str(&format!("{:?}", ct))?; + if print_ty { + fmt.write_str(&format!(": {}", ty))?; + } Ok(()) }) } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 739c543dea7..a81a60df2be 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -454,7 +454,12 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ConstValue::ByRef { .. } => format!("ByRef(..)"), }; - let kind = match literal { + let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree { + ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf), + ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"), + }; + + let val = match literal { ConstantKind::Ty(ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("Param({})", p), ty::ConstKind::Unevaluated(uv) => format!( @@ -463,7 +468,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { uv.substs, uv.promoted, ), - ty::ConstKind::Value(val) => format!("Value({})", fmt_val(&val)), + ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)), ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. ty::ConstKind::Placeholder(_) @@ -665,7 +670,8 @@ pub fn write_allocations<'tcx>( ) -> impl DoubleEndedIterator<Item = AllocId> + '_ { alloc.inner().relocations().values().map(|id| *id) } - fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ { + + fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ { match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => { Either::Left(Either::Left(std::iter::once(ptr.provenance))) @@ -681,17 +687,11 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet<AllocId>); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) { - if let ty::ConstKind::Value(val) = c.kind() { - self.0.extend(alloc_ids_from_const(val)); - } - } - fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) { match c.literal { ConstantKind::Ty(c) => self.visit_const(c, loc), ConstantKind::Val(val, _) => { - self.0.extend(alloc_ids_from_const(val)); + self.0.extend(alloc_ids_from_const_val(val)); } } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 01945b543b1..da4793fa039 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::{self, Body, Promoted}; +use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::vec_map::VecMap; @@ -427,7 +427,7 @@ pub struct DestructuredConst<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredMirConstant<'tcx> { pub variant: Option<VariantIdx>, - pub fields: &'tcx [mir::ConstantKind<'tcx>], + pub fields: &'tcx [ConstantKind<'tcx>], } /// Coverage information summarized from a MIR if instrumented for source code coverage (see diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c859d93043e..c65e79a80fb 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,3 +1,4 @@ +use crate::mir; use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -676,7 +677,7 @@ impl<'tcx> TerminatorKind<'tcx> { .values .iter() .map(|&u| { - ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) + mir::ConstantKind::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) .to_string() .into() }) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5b48f164016..22b1ad41904 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -968,7 +968,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>> ) -> EvalToValTreeResult<'tcx> { desc { "evaluate type-level constant" } - remap_env_constness } /// Converts a type level constant value into `ConstValue` @@ -980,7 +979,7 @@ rustc_queries! { /// field values or return `None` if constant is invalid. /// /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid. - query try_destructure_const(key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>) -> Option<mir::DestructuredConst<'tcx>> { + query try_destructure_const(key: ty::Const<'tcx>) -> Option<mir::DestructuredConst<'tcx>> { desc { "destructure type level constant"} } @@ -993,15 +992,6 @@ rustc_queries! { /// Dereference a constant reference or raw pointer and turn the result into a constant /// again. - query deref_const( - key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>> - ) -> ty::Const<'tcx> { - desc { "deref constant" } - remap_env_constness - } - - /// Dereference a constant reference or raw pointer and turn the result into a constant - /// again. query deref_mir_constant( key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> ) -> mir::ConstantKind<'tcx> { diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index 015bdb5783f..70abdb9ab4c 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -5,7 +5,6 @@ //! its name suggest, is to provide an abstraction boundary for creating //! interned Chalk types. -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::{self, AdtDef, TyCtxt}; use rustc_hir::def_id::DefId; @@ -62,7 +61,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { type InternedType = Box<chalk_ir::TyData<Self>>; type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>; type InternedConst = Box<chalk_ir::ConstData<Self>>; - type InternedConcreteConst = ConstValue<'tcx>; + type InternedConcreteConst = ty::ValTree<'tcx>; type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>; type InternedGoal = Box<chalk_ir::GoalData<Self>>; type InternedGoals = Vec<chalk_ir::Goal<Self>>; diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 0e87a05bade..47abbb723dc 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,5 +1,5 @@ -use crate::mir::interpret::ConstValue; -use crate::mir::interpret::{LitToConstInput, Scalar}; +use crate::mir::interpret::LitToConstInput; +use crate::mir::ConstantKind; use crate::ty::{ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, @@ -195,14 +195,13 @@ impl<'tcx> Const<'tcx> { /// Interns the given value as a constant. #[inline] - pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self { + pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self { tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty }) } - #[inline] - /// Interns the given scalar as a constant. - pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self { - Self::from_value(tcx, ConstValue::Scalar(val), ty) + pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt, ty: Ty<'tcx>) -> Self { + let valtree = ty::ValTree::from_scalar_int(i); + Self::from_value(tcx, valtree, ty) } #[inline] @@ -212,13 +211,14 @@ impl<'tcx> Const<'tcx> { .layout_of(ty) .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) .size; - Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value) + Self::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap(), ty.value) } #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - Self::from_scalar(tcx, Scalar::ZST, ty) + let valtree = ty::ValTree::zst(); + Self::from_value(tcx, valtree, ty) } #[inline] @@ -263,17 +263,32 @@ impl<'tcx> Const<'tcx> { /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> { - if let Some(val) = self.kind().try_eval(tcx, param_env) { + if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) { match val { Ok(val) => Const::from_value(tcx, val, self.ty()), Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()), } } else { + // Either the constant isn't evaluatable or ValTree creation failed. self } } #[inline] + /// Tries to evaluate the constant if it is `Unevaluated` and creates a ConstValue if the + /// evaluation succeeds. If it doesn't succeed, returns the unevaluated constant. + pub fn eval_for_mir(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> ConstantKind<'tcx> { + if let Some(val) = self.val().try_eval_for_mir(tcx, param_env) { + match val { + Ok(const_val) => ConstantKind::from_value(const_val, self.ty()), + Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())), + } + } else { + ConstantKind::Ty(self) + } + } + + #[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: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { self.try_eval_bits(tcx, param_env, ty) diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 35d286d2c57..10d03065c79 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -63,7 +63,7 @@ pub enum ConstKind<'tcx> { Unevaluated(Unevaluated<'tcx>), /// Used to hold computed value. - Value(ConstValue<'tcx>), + Value(ty::ValTree<'tcx>), /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. @@ -75,7 +75,7 @@ static_assert_size!(ConstKind<'_>, 40); impl<'tcx> ConstKind<'tcx> { #[inline] - pub fn try_to_value(self) -> Option<ConstValue<'tcx>> { + pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> { if let ConstKind::Value(val) = self { Some(val) } else { None } } @@ -86,7 +86,7 @@ impl<'tcx> ConstKind<'tcx> { #[inline] pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - Some(self.try_to_value()?.try_to_scalar()?.assert_int()) + self.try_to_value()?.try_to_scalar_int() } #[inline] @@ -115,23 +115,65 @@ pub enum InferConst<'tcx> { Fresh(u32), } +enum EvalMode { + Typeck, + Mir, +} + +enum EvalResult<'tcx> { + ValTree(ty::ValTree<'tcx>), + ConstVal(ConstValue<'tcx>), +} + impl<'tcx> ConstKind<'tcx> { #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) + self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) } #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary /// return `None`. // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. - pub fn try_eval( + pub fn try_eval_for_mir( self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { + Some(Ok(EvalResult::ValTree(_))) => unreachable!(), + Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + /// return `None`. + // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. + pub fn try_eval_for_typeck( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) { + Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)), + Some(Ok(EvalResult::ConstVal(_))) => unreachable!(), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + fn try_eval_inner( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + eval_mode: EvalMode, + ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; @@ -166,14 +208,29 @@ impl<'tcx> ConstKind<'tcx> { let (param_env, unevaluated) = param_env_and.into_parts(); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - match tcx.const_eval_resolve(param_env, unevaluated, None) { - // NOTE(eddyb) `val` contains no lifetimes/types/consts, - // and we use the original type, so nothing from `substs` - // (which may be identity substs, see above), - // can leak through `val` into the const we return. - Ok(val) => Some(Ok(val)), - Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e)), + match eval_mode { + EvalMode::Typeck => { + match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ValTree(val?))), + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e)), + } + } + EvalMode::Mir => { + match tcx.const_eval_resolve(param_env, unevaluated, None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ConstVal(val))), + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e)), + } + } } } else { None diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 418848f69d7..973dc3dd4a1 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,4 +1,6 @@ use super::ScalarInt; +use crate::mir::interpret::{AllocId, Scalar}; +use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] @@ -50,4 +52,61 @@ impl<'tcx> ValTree<'tcx> { _ => bug!("expected branch, got {:?}", self), } } + + pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self { + let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b))); + let interned = tcx.arena.alloc_from_iter(branches); + + Self::Branch(interned) + } + + pub fn from_scalar_int(i: ScalarInt) -> Self { + Self::Leaf(i) + } + + pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { + self.try_to_scalar_int().map(Scalar::Int) + } + + pub fn try_to_scalar_int(self) -> Option<ScalarInt> { + match self { + Self::Leaf(s) => Some(s), + Self::Branch(_) => None, + } + } + + pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { + self.try_to_scalar_int().map(|s| s.try_to_machine_usize(tcx).ok()).flatten() + } + + /// Get the values inside the ValTree as a slice of bytes. This only works for + /// constants with types &str and &[u8]. + pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { + match ty.kind() { + ty::Ref(_, inner_ty, _) => match inner_ty.kind() { + ty::Str => { + let leafs = self + .unwrap_branch() + .into_iter() + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) + .collect::<Vec<_>>(); + + return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + } + ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => { + let leafs = self + .unwrap_branch() + .into_iter() + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) + .collect::<Vec<_>>(); + + return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + } + _ => {} + }, + _ => {} + } + + None + } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5c0cf534b80..0930f3edf72 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -8,7 +8,7 @@ use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; use crate::middle::stability; -use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar}; +use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, }; @@ -991,7 +991,7 @@ impl<'tcx> CommonConsts<'tcx> { CommonConsts { unit: mk_const(ty::ConstS { - kind: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)), + kind: ty::ConstKind::Value(ty::ValTree::zst()), ty: types.unit, }), } @@ -1186,11 +1186,7 @@ impl<'tcx> TyCtxt<'tcx> { }; debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( - &[ - ast::NestedMetaItem::Literal(ast::Lit { - kind: ast::LitKind::Int(a, _), .. - }), - ], + &[ast::NestedMetaItem::Literal(ast::Lit { kind: ast::LitKind::Int(a, _), .. })], ) = attr.meta_item_list().as_deref() { Bound::Included(a) @@ -1663,7 +1659,7 @@ macro_rules! nop_lift { impl<'a, 'tcx> Lift<'tcx> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0)) { + if tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0 .0)) { // SAFETY: `self` is interned and therefore valid // for the entire lifetime of the `TyCtxt`. Some(unsafe { mem::transmute(self) }) @@ -2248,7 +2244,11 @@ impl<'tcx> TyCtxt<'tcx> { /// `*r == kind`. #[inline] pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> { - if *r == kind { r } else { self.mk_region(kind) } + if *r == kind { + r + } else { + self.mk_region(kind) + } } #[allow(rustc::usage_of_ty_tykind)] @@ -2268,7 +2268,11 @@ impl<'tcx> TyCtxt<'tcx> { pred: Predicate<'tcx>, binder: Binder<'tcx, PredicateKind<'tcx>>, ) -> Predicate<'tcx> { - if pred.kind() != binder { self.mk_predicate(binder) } else { pred } + if pred.kind() != binder { + self.mk_predicate(binder) + } else { + pred + } } pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> { @@ -2413,7 +2417,11 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } + if self.features().never_type_fallback { + self.types.never + } else { + self.types.unit + } } #[inline] @@ -2564,11 +2572,9 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[ty::Binder<'tcx, ExistentialPredicate<'tcx>>], ) -> &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> { assert!(!eps.is_empty()); - assert!( - eps.array_windows() - .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) - != Ordering::Greater) - ); + assert!(eps + .array_windows() + .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) != Ordering::Greater)); self._intern_poly_existential_predicates(eps) } @@ -2601,29 +2607,49 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List<GenericArg<'tcx>> { - if ts.is_empty() { List::empty() } else { self._intern_substs(ts) } + if ts.is_empty() { + List::empty() + } else { + self._intern_substs(ts) + } } pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List<ProjectionKind> { - if ps.is_empty() { List::empty() } else { self._intern_projs(ps) } + if ps.is_empty() { + List::empty() + } else { + self._intern_projs(ps) + } } pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> { - if ts.is_empty() { List::empty() } else { self._intern_place_elems(ts) } + if ts.is_empty() { + List::empty() + } else { + self._intern_place_elems(ts) + } } pub fn intern_canonical_var_infos( self, ts: &[CanonicalVarInfo<'tcx>], ) -> CanonicalVarInfos<'tcx> { - if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } + if ts.is_empty() { + List::empty() + } else { + self._intern_canonical_var_infos(ts) + } } pub fn intern_bound_variable_kinds( self, ts: &[ty::BoundVariableKind], ) -> &'tcx List<ty::BoundVariableKind> { - if ts.is_empty() { List::empty() } else { self._intern_bound_variable_kinds(ts) } + if ts.is_empty() { + List::empty() + } else { + self._intern_bound_variable_kinds(ts) + } } pub fn mk_fn_sig<I>( diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b7130e69f35..e8dd179eac1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -369,7 +369,6 @@ impl<'tcx> Instance<'tcx> { } // This should be kept up to date with `resolve`. - #[instrument(level = "debug", skip(tcx))] pub fn resolve_opt_const_arg( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7f0f3755c4b..8da447d16fb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2161,22 +2161,28 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. + #[instrument(skip(self), level = "debug")] pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => match self.def_kind(def.did) { - DefKind::Const - | DefKind::Static(..) - | DefKind::AssocConst - | DefKind::Ctor(..) - | DefKind::AnonConst - | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), - // If the caller wants `mir_for_ctfe` of a function they should not be using - // `instance_mir`, so we'll assume const fn also wants the optimized version. - _ => { - assert_eq!(def.const_param_did, None); - self.optimized_mir(def.did) + ty::InstanceDef::Item(def) => { + debug!("calling def_kind on def: {:?}", def); + let def_kind = self.def_kind(def.did); + debug!("returned from def_kind: {:?}", def_kind); + match def_kind { + DefKind::Const + | DefKind::Static(..) + | DefKind::AssocConst + | DefKind::Ctor(..) + | DefKind::AnonConst + | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), + // If the caller wants `mir_for_ctfe` of a function they should not be using + // `instance_mir`, so we'll assume const fn also wants the optimized version. + _ => { + assert_eq!(def.const_param_did, None); + self.optimized_mir(def.did) + } } - }, + } ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 5ad93d77820..7a096bbc4d9 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -98,7 +98,6 @@ pub trait Printer<'tcx>: Sized { // Defaults (should not be overridden): - #[instrument(skip(self), level = "debug")] fn default_print_def_path( self, def_id: DefId, @@ -302,6 +301,7 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> { impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { type Output = P::Type; type Error = P::Error; + fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { cx.print_type(*self) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 05f332cdd5f..3b11f7572a6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,4 +1,4 @@ -use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar}; +use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{ self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable, @@ -607,7 +607,11 @@ pub trait PrettyPrinter<'tcx>: } } } else { - if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } + if verbose { + p!(write("{:?}", infer_ty)) + } else { + p!(write("{}", infer_ty)) + } } } ty::Error(_) => p!("[type error]"), @@ -1224,7 +1228,7 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), ty::ConstKind::Value(value) => { - return self.pretty_print_const_value(value, ct.ty(), print_ty); + return self.pretty_print_const_valtree(value, ct.ty(), print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1262,7 +1266,7 @@ pub trait PrettyPrinter<'tcx>: ty::Ref(_, inner, _) => { if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { - if let ty::ConstKind::Value(ConstValue::Scalar(int)) = len.kind() { + if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { match self.tcx().get_global_alloc(alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); @@ -1331,7 +1335,11 @@ pub trait PrettyPrinter<'tcx>: 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)) } + if print_ty { + p!(write("{:#?}", int)) + } else { + p!(write("{:?}", int)) + } } // Char ty::Char if char::try_from(int).is_ok() => { @@ -1408,85 +1416,64 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } - fn pretty_print_const_value( + fn pretty_print_const_valtree( mut self, - ct: ConstValue<'tcx>, + valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>, print_ty: bool, ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); if self.tcx().sess.verbose() { - p!(write("ConstValue({:?}: ", ct), print(ty), ")"); + p!(write("ValTree({:?}: ", valtree), print(ty), ")"); return Ok(self); } let u8_type = self.tcx().types.u8; - - match (ct, ty.kind()) { - // Byte/string slices, printed as (byte) string literals. - (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => { - match inner.kind() { - ty::Slice(t) => { - if *t == u8_type { - // The `inspect` here is okay since we checked the bounds, and there are - // no relocations (we have an active slice reference here). We don't use - // this result to affect interpreter execution. - let byte_str = data - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(start..end); - return self.pretty_print_byte_str(byte_str); - } - } - ty::Str => { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this - // result to affect interpreter execution. - let slice = data - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(start..end); - p!(write("{:?}", String::from_utf8_lossy(slice))); - return Ok(self); - } - _ => {} + match (valtree, ty.kind()) { + (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { + ty::Slice(t) if *t == u8_type => { + let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + bug!( + "expected to convert valtree {:?} to raw bytes for type {:?}", + valtree, + t + ) + }); + return self.pretty_print_byte_str(bytes); } - } - (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { - let n = n.kind().try_to_bits(self.tcx().data_layout.pointer_size).unwrap(); - // cast is ok because we already checked for pointer size (32 or 64 bit) above - let range = AllocRange { start: offset, size: Size::from_bytes(n) }; - - let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap(); + ty::Str => { + let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + bug!("expected to convert valtree to raw bytes for type {:?}", ty) + }); + p!(write("{:?}", String::from_utf8_lossy(bytes))); + return Ok(self); + } + _ => {} + }, + (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { + let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| { + bug!("expected to convert valtree to raw bytes for type {:?}", t) + }); p!("*"); - p!(pretty_print_byte_str(byte_str)); + p!(pretty_print_byte_str(bytes)); return Ok(self); } - // Aggregates, printed as array/tuple/struct/variant construction syntax. - // - // NB: the `has_param_types_or_consts` check ensures that we can use - // the `destructure_const` query with an empty `ty::ParamEnv` without - // introducing ICEs (e.g. via `layout_of`) from missing bounds. - // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` - // to be able to destructure the tuple into `(0u8, *mut T) - // - // 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() => { + (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) + if !ty.has_param_types_or_consts() => + { let Some(contents) = self.tcx().try_destructure_const( - ty::ParamEnv::reveal_all() - .and(self.tcx().mk_const(ty::ConstS { kind: ty::ConstKind::Value(ct), ty })), + ty::Const::from_value(self.tcx(), valtree, ty) ) else { // Fall back to debug pretty printing for invalid constants. - p!(write("{:?}", ct)); + p!(write("{:?}", valtree)); if print_ty { p!(": ", print(ty)); } return Ok(self); }; - let fields = contents.fields.iter().copied(); - match *ty.kind() { ty::Array(..) => { p!("[", comma_sep(fields), "]"); @@ -1513,7 +1500,6 @@ pub trait PrettyPrinter<'tcx>: contents.variant.expect("destructed const of adt without variant idx"); let variant_def = &def.variant(variant_idx); p!(print_value_path(variant_def.def_id, substs)); - match variant_def.ctor_kind { CtorKind::Const => {} CtorKind::Fn => { @@ -1535,21 +1521,20 @@ pub trait PrettyPrinter<'tcx>: } _ => unreachable!(), } - return Ok(self); } - - (ConstValue::Scalar(scalar), _) => { - return self.pretty_print_const_scalar(scalar, ty, print_ty); + (ty::ValTree::Leaf(leaf), _) => { + return self.pretty_print_const_scalar_int(leaf, ty, print_ty); } - // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. _ => {} } // fallback - p!(write("{:?}", ct)); + if valtree != ty::ValTree::zst() { + p!(write("{:?}", valtree)); + } if print_ty { p!(": ", print(ty)); } @@ -2296,7 +2281,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { Ok(inner) } - #[instrument(skip(self), level = "debug")] fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<'tcx>, @@ -2309,9 +2293,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { type BreakTy = (); - #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - trace!("address: {:p}", r.0.0); + trace!("address: {:p}", r.0 .0); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.used_region_names.insert(name); } else if let ty::RePlaceholder(ty::PlaceholderRegion { @@ -2326,7 +2309,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // We collect types in order to prevent really large types from compiling for // a really long time. See issue #83150 for why this is necessary. - #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { let not_previously_inserted = self.type_collector.insert(ty); if not_previously_inserted { @@ -2353,6 +2335,7 @@ where { type Output = P; type Error = P::Error; + fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { cx.in_binder(self) } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 31103b8d77e..51980acd38f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -4,7 +4,6 @@ //! 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, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable}; @@ -613,9 +612,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index, (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - check_const_value_eq(relation, a_val, b_val, a, b)? - } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().generic_const_exprs => @@ -649,66 +646,6 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } } -fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a_val: ConstValue<'tcx>, - b_val: ConstValue<'tcx>, - // FIXME(oli-obk): these arguments should go away with valtrees - a: ty::Const<'tcx>, - b: 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, _a_size)), - ConstValue::Scalar(Scalar::Ptr(b_val, _b_size)), - ) => { - a_val == b_val - || match (tcx.global_alloc(a_val.provenance), tcx.global_alloc(b_val.provenance)) { - (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 { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. }) - if a.ty().is_ref() || b.ty().is_ref() => - { - if a.ty().is_ref() && b.ty().is_ref() { - alloc_a == alloc_b - } else { - false - } - } - (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 iter::zip(a_destructured.fields, b_destructured.fields) { - relation.consts(*a_field, *b_field)?; - } - - true - } else { - false - } - } - - _ => false, - }) -} - impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, 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 a87134d1f52..3d6e50f0c06 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,12 +1,16 @@ //! See docs in build/expr/mod.rs -use crate::build::{lit_to_mir_constant, Builder}; +use crate::build::{parse_float_into_constval, Builder}; +use rustc_ast as ast; use rustc_hir::def_id::DefId; -use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar}; +use rustc_middle::mir::interpret::{ + Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, +}; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; +use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that @@ -84,3 +88,54 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } + +#[instrument(skip(tcx, lit_input))] +pub(crate) fn lit_to_mir_constant<'tcx>( + tcx: TyCtxt<'tcx>, + lit_input: LitToConstInput<'tcx>, +) -> Result<ConstantKind<'tcx>, LitToConstError> { + let LitToConstInput { lit, ty, neg } = lit_input; + let trunc = |n| { + let param_ty = ty::ParamEnv::reveal_all().and(ty); + let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; + trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); + let result = width.truncate(n); + trace!("trunc result: {}", result); + Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) + }; + + let value = match (lit, &ty.kind()) { + (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { + let s = s.as_str(); + let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: s.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Slice(_)) => + { + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: data.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + let id = tcx.allocate_bytes(data); + ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) + } + (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { + ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + } + (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? + } + (ast::LitKind::Float(n, _), ty::Float(fty)) => { + parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)? + } + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + _ => return Err(LitToConstError::TypeError), + }; + + Ok(ConstantKind::Val(value, ty)) +} diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 793066e43c3..51f7aa642c8 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,7 +1,7 @@ use crate::build; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; -use crate::thir::constant::parse_float; +use crate::thir::constant::parse_float_into_scalar; use crate::thir::pattern::pat_from_hir; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -14,14 +14,16 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; -use rustc_middle::mir::interpret::Allocation; -use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar}; +use rustc_middle::mir::interpret::{ + Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, +}; use rustc_middle::mir::*; use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -266,57 +268,6 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ }) } -#[instrument(skip(tcx, lit_input))] -pub(crate) fn lit_to_mir_constant<'tcx>( - tcx: TyCtxt<'tcx>, - lit_input: LitToConstInput<'tcx>, -) -> Result<ConstantKind<'tcx>, LitToConstError> { - let LitToConstInput { lit, ty, neg } = lit_input; - let trunc = |n| { - let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; - trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); - let result = width.truncate(n); - trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) - }; - - let value = match (lit, &ty.kind()) { - (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { - let s = s.as_str(); - let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: s.len() } - } - (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Slice(_)) => - { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: data.len() } - } - (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) - } - (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) - } - (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? - } - (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)? - } - (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), - (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), - _ => return Err(LitToConstError::TypeError), - }; - - Ok(ConstantKind::Val(value, ty)) -} - /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from @@ -1137,6 +1088,65 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } +fn parse_float_into_constval<'tcx>( + num: Symbol, + float_ty: ty::FloatTy, + neg: bool, +) -> Option<ConstValue<'tcx>> { + parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar) +} + +#[instrument(skip(tcx, lit_input))] +pub(crate) fn lit_to_mir_constant<'tcx>( + tcx: TyCtxt<'tcx>, + lit_input: LitToConstInput<'tcx>, +) -> Result<ConstantKind<'tcx>, LitToConstError> { + let LitToConstInput { lit, ty, neg } = lit_input; + let trunc = |n| { + let param_ty = ty::ParamEnv::reveal_all().and(ty); + let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; + trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); + let result = width.truncate(n); + trace!("trunc result: {}", result); + Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) + }; + + let value = match (lit, &ty.kind()) { + (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { + let s = s.as_str(); + let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: s.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Slice(_)) => + { + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: data.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + let id = tcx.allocate_bytes(data); + ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) + } + (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { + ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + } + (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? + } + (ast::LitKind::Float(n, _), ty::Float(fty)) => { + parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)? + } + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + _ => return Err(LitToConstError::TypeError), + }; + + Ok(ConstantKind::Val(value, ty)) +} + /////////////////////////////////////////////////////////////////////////// // Builder methods are broken up into modules, depending on what kind // of thing is being lowered. Note that they use the `unpack` macro diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index d82e6688633..cfb09ecedd6 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,13 +1,10 @@ +use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_ast as ast; -use rustc_middle::mir::interpret::{ - Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, -}; -use rustc_middle::ty::{self, ParamEnv, TyCtxt}; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput, Scalar}; +use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt}; use rustc_span::symbol::Symbol; -use rustc_target::abi::Size; -// FIXME Once valtrees are available, get rid of this function and the query pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, @@ -20,58 +17,59 @@ pub(crate) fn lit_to_const<'tcx>( trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) + + Ok(ScalarInt::try_from_uint(result, width) + .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))) }; - let lit = match (lit, &ty.kind()) { + let valtree = match (lit, &ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { - let s = s.as_str(); - let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: s.len() } + let str_bytes = s.as_str().as_bytes(); + ty::ValTree::from_raw_bytes(tcx, str_bytes) } (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: data.len() } + let bytes = data as &[u8]; + ty::ValTree::from_raw_bytes(tcx, bytes) } (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) + let bytes = data as &[u8]; + ty::ValTree::from_raw_bytes(tcx, bytes) } (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + ty::ValTree::from_scalar_int((*n).into()) } (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? + let scalar_int = + trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?; + ty::ValTree::from_scalar_int(scalar_int) } (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)? + parse_float_into_valtree(*n, *fty, neg).ok_or(LitToConstError::Reported)? } - (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), - (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), + (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), _ => return Err(LitToConstError::TypeError), }; - Ok(ty::Const::from_value(tcx, lit, ty)) + + Ok(ty::Const::from_value(tcx, valtree, ty)) } -// FIXME move this to rustc_mir_build::build -pub(crate) fn parse_float<'tcx>( +pub(crate) fn parse_float_into_scalar( num: Symbol, - fty: ty::FloatTy, + float_ty: ty::FloatTy, neg: bool, -) -> Option<ConstValue<'tcx>> { +) -> Option<Scalar> { let num = num.as_str(); - use rustc_apfloat::ieee::{Double, Single}; - let scalar = match fty { + match float_ty { ty::FloatTy::F32 => { let Ok(rust_f) = num.parse::<f32>() else { return None }; let mut f = num.parse::<Single>().unwrap_or_else(|e| { panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) }); + assert!( u128::from(rust_f.to_bits()) == f.to_bits(), "apfloat::ieee::Single gave different result for `{}`: \ @@ -82,16 +80,19 @@ pub(crate) fn parse_float<'tcx>( Single::from_bits(rust_f.to_bits().into()), rust_f.to_bits() ); + if neg { f = -f; } - Scalar::from_f32(f) + + Some(Scalar::from_f32(f)) } ty::FloatTy::F64 => { let Ok(rust_f) = num.parse::<f64>() else { return None }; let mut f = num.parse::<Double>().unwrap_or_else(|e| { panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) }); + assert!( u128::from(rust_f.to_bits()) == f.to_bits(), "apfloat::ieee::Double gave different result for `{}`: \ @@ -102,12 +103,20 @@ pub(crate) fn parse_float<'tcx>( Double::from_bits(rust_f.to_bits().into()), rust_f.to_bits() ); + if neg { f = -f; } - Scalar::from_f64(f) + + Some(Scalar::from_f64(f)) } - }; + } +} - Some(ConstValue::Scalar(scalar)) +fn parse_float_into_valtree<'tcx>( + num: Symbol, + float_ty: ty::FloatTy, + neg: bool, +) -> Option<ty::ValTree<'tcx>> { + parse_float_into_scalar(num, float_ty, neg).map(|s| ty::ValTree::Leaf(s.try_to_int().unwrap())) } 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 f694e009ab9..b423c645447 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 @@ -371,6 +371,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } ty::Adt(adt_def, substs) if adt_def.is_enum() => { let destructured = tcx.destructure_mir_constant(param_env, cv); + PatKind::Variant { adt_def: *adt_def, substs, @@ -502,7 +503,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // deref pattern. _ => { if !pointee_ty.is_sized(tcx.at(span), param_env) { - // `tcx.deref_const()` below will ICE with an unsized type + // `tcx.deref_mirconstant()` below will ICE with an unsized type // (except slices, which are handled in a separate arm above). let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty); if self.include_lint_checks { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 83175439b70..e28cb67217c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -185,11 +185,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } (Some(PatKind::Constant { value: lo }), None) => { let hi = ty.numeric_max_val(self.tcx)?; - Some((*lo, hi.into())) + Some((*lo, mir::ConstantKind::from_const(hi, self.tcx))) } (None, Some(PatKind::Constant { value: hi })) => { let lo = ty.numeric_min_val(self.tcx)?; - Some((lo.into(), *hi)) + Some((mir::ConstantKind::from_const(lo, self.tcx), *hi)) } _ => None, } @@ -798,11 +798,12 @@ pub(crate) fn compare_const_vals<'tcx>( if let ty::Str = ty.kind() && let ( Some(a_val @ ConstValue::Slice { .. }), Some(b_val @ ConstValue::Slice { .. }), - ) = (a.try_val(), b.try_val()) + ) = (a.try_val(tcx), b.try_val(tcx)) { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); return from_bool(a_bytes == b_bytes); } + fallback() } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 027af5b9c1f..8d16c5f22c3 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -1032,7 +1032,7 @@ where Operand::Constant(Box::new(Constant { span: self.source_info.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx(), val.into()).into(), + literal: ConstantKind::from_usize(self.tcx(), val.into()), })) } diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index 3577b3d2d80..8944ebed9a7 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for ConstDebugInfo { sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0 } - fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running ConstDebugInfo on {:?}", body.source); for (local, constant) in find_optimization_oportunities(body) { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 2529a7c4232..412a5b4fc91 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -67,6 +67,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { true } + #[instrument(skip(self, tcx), level = "debug")] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // will be evaluated by miri and produce its errors there if body.source.promoted.is_some() { @@ -687,7 +688,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).into(), + literal: ConstantKind::from_scalar(self.tcx, scalar, ty), })) } @@ -765,20 +766,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let Some(Some(alloc)) = alloc { // Assign entire constant in a single statement. // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`. + let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO }; + let literal = ConstantKind::Val(const_val, ty); *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { span: source_info.span, user_ty: None, - literal: self - .ecx - .tcx - .mk_const(ty::ConstS { - ty, - kind: ty::ConstKind::Value(ConstValue::ByRef { - alloc, - offset: Size::ZERO, - }), - }) - .into(), + literal, }))); } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 8a9f2107316..e0e27c53f18 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -470,7 +470,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).into(), + literal: ConstantKind::from_bool(self.tcx, val), }))) } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 89895fddd0c..f3c67319596 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -991,7 +991,7 @@ fn insert_panic_block<'tcx>( cond: Operand::Constant(Box::new(Constant { span: body.span, user_ty: None, - literal: ty::Const::from_bool(tcx, false).into(), + literal: ConstantKind::from_bool(tcx, false), })), expected: true, msg: message, diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 4fbb7643378..ea10ec5f25c 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -3,8 +3,8 @@ use crate::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::{ - BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - Statement, StatementKind, Terminator, TerminatorKind, UnOp, + BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp, }; use rustc_middle::ty::{self, TyCtxt}; @@ -129,8 +129,8 @@ impl<'tcx> InstCombineContext<'tcx, '_> { return; } - let constant = - Constant { span: source_info.span, literal: len.into(), user_ty: None }; + let literal = ConstantKind::from_const(len, self.tcx); + let constant = Constant { span: source_info.span, literal, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0e52da57e60..b8932251465 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -531,8 +531,10 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { None => {} Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), } + debug!("about to call mir_drops_elaborated..."); let mut body = tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); + debug!("body: {:#?}", body); run_optimization_passes(tcx, &mut body); debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 65801069560..989b94b68c1 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -34,7 +34,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { Rvalue::Use(Operand::Constant(Box::new(Constant { span: terminator.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), + literal: ConstantKind::zero_sized(tcx.types.unit), }))), ))), }); diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index f925d13b2fb..89808d3d4cd 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -15,7 +15,7 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { sess.panic_strategy() != PanicStrategy::Abort } - fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("remove_noop_landing_pads({:?})", body); self.remove_nop_landing_pads(body) } @@ -81,6 +81,8 @@ impl RemoveNoopLandingPads { } fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { + debug!("body: {:#?}", body); + // make sure there's a single resume block let resume_block = { let patch = MirPatch::new(body); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 78a4ece2ecb..3be1783ae33 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -430,7 +430,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { let func = Operand::Constant(Box::new(Constant { span: self.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, func_ty).into(), + literal: ConstantKind::zero_sized(func_ty), })); let ref_loc = self.make_place( @@ -630,7 +630,7 @@ fn build_call_shim<'tcx>( Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty).into(), + literal: ConstantKind::zero_sized(ty), })), rcvr.into_iter().collect::<Vec<_>>(), ) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index dfaf464587b..2af22e129a5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -323,6 +323,7 @@ impl<'tcx> InliningMap<'tcx> { } } +#[instrument(skip(tcx, mode), level = "debug")] pub fn collect_crate_mono_items( tcx: TyCtxt<'_>, mode: MonoItemCollectionMode, @@ -362,6 +363,7 @@ pub fn collect_crate_mono_items( // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. +#[instrument(skip(tcx, mode), level = "debug")] fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> { debug!("collecting roots"); let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() }; @@ -400,6 +402,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a /// post-monorphization error is encountered during a collection step. +#[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")] fn collect_items_rec<'tcx>( tcx: TyCtxt<'tcx>, starting_point: Spanned<MonoItem<'tcx>>, @@ -752,13 +755,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { /// This does not walk the constant, as it has been handled entirely here and trying /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily /// work, as some constants cannot be represented in the type system. + #[instrument(skip(self), level = "debug")] fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { let literal = self.monomorphize(constant.literal); let val = match literal { mir::ConstantKind::Val(val, _) => val, mir::ConstantKind::Ty(ct) => match ct.kind() { - ty::ConstKind::Value(val) => val, + ty::ConstKind::Value(val) => self.tcx.valtree_to_const_val((ct.ty(), val)), ty::ConstKind::Unevaluated(ct) => { + debug!(?ct); let param_env = ty::ParamEnv::reveal_all(); match self.tcx.const_eval_resolve(param_env, ct, None) { // The `monomorphize` call should have evaluated that constant already. @@ -778,6 +783,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.visit_ty(literal.ty(), TyContext::Location(location)); } + #[instrument(skip(self), level = "debug")] fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", constant, location); @@ -785,7 +791,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let param_env = ty::ParamEnv::reveal_all(); match substituted_constant.kind() { - ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), + ty::ConstKind::Value(val) => { + let const_val = self.tcx.valtree_to_const_val((constant.ty(), val)); + collect_const_value(self.tcx, const_val, self.output) + } ty::ConstKind::Unevaluated(unevaluated) => { match self.tcx.const_eval_resolve(param_env, unevaluated, None) { // The `monomorphize` call should have evaluated that constant already. @@ -1120,6 +1129,7 @@ fn find_vtable_types_for_unsizing<'tcx>( } } +#[instrument(skip(tcx), level = "debug")] fn create_fn_mono_item<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -1133,7 +1143,10 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } - respan(source, MonoItem::Fn(instance.polymorphize(tcx))) + let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx))); + debug!(?respanned); + + respanned } /// Creates a `MonoItem` for each method that is referenced by the vtable for @@ -1275,6 +1288,7 @@ impl<'v> RootCollector<'_, 'v> { /// If `def_id` represents a root, pushes it onto the list of /// outputs. (Note that all roots must be monomorphic.) + #[instrument(skip(self), level = "debug")] fn push_if_root(&mut self, def_id: LocalDefId) { if self.is_root(def_id) { debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); @@ -1415,17 +1429,17 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte } /// Scans the MIR in order to find function calls, closures, and drop-glue. +#[instrument(skip(tcx, output), level = "debug")] fn collect_neighbours<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, output: &mut MonoItems<'tcx>, ) { - debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); - MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); } +#[instrument(skip(tcx, output), level = "debug")] fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 2f7e413b087..f67b87a6a52 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,7 +1,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; @@ -30,6 +29,7 @@ pub(super) fn mangle<'tcx>( match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { instance_ty = tcx.type_of(ty_def_id); + debug!(?instance_ty); break; } _ => { @@ -261,10 +261,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { // only print integers match (ct.kind(), ct.ty().kind()) { - ( - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(scalar))), - ty::Int(_) | ty::Uint(_), - ) => { + (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => { // The `pretty_print_const` formatting depends on -Zverbose // flag, so we cannot reuse it here. let signed = matches!(ct.ty().kind(), ty::Int(_)); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f79f7a4ebdf..ff070636797 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -5,7 +5,6 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; @@ -604,16 +603,18 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { if let Some(&i) = self.consts.get(&ct) { return self.print_backref(i); } + let start = self.out.len(); + let ty = ct.ty(); - match ct.ty().kind() { + match ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { - self = ct.ty().print(self)?; + self = ty.print(self)?; - let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty()); + let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty); // Negative integer values are mangled using `n` as a "sign prefix". - if let ty::Int(ity) = ct.ty().kind() { + if let ty::Int(ity) = ty.kind() { let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { @@ -626,45 +627,57 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } // HACK(eddyb) because `ty::Const` only supports sized values (for now), - // we can't use `deref_const` + supporting `str`, we have to specially + // we can't use dereference the const + supporting `str`, we have to specially // handle `&str` and include both `&` ("R") and `str` ("e") prefixes. - ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => { - self.push("R"); - match ct.kind() { - ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { - // NOTE(eddyb) the following comment was kept from `ty::print::pretty`: - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this - // result to affect interpreter execution. - let slice = data - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(start..end); - let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); - - self.push("e"); - // FIXME(eddyb) use a specialized hex-encoding loop. - for byte in s.bytes() { - let _ = write!(self.out, "{:02x}", byte); + ty::Ref(_, inner_ty, mutbl) => { + self.push(match mutbl { + hir::Mutability::Not => "R", + hir::Mutability::Mut => "Q", + }); + + match inner_ty.kind() { + ty::Str if *mutbl == hir::Mutability::Not => { + match ct.kind() { + ty::ConstKind::Value(valtree) => { + let slice = + valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + bug!( + "expected to get raw bytes from valtree {:?} for type {:}", + valtree, ty + ) + }); + let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); + + self.push("e"); + + // FIXME(eddyb) use a specialized hex-encoding loop. + for byte in s.bytes() { + let _ = write!(self.out, "{:02x}", byte); + } + + self.push("_"); + } + + _ => { + bug!("symbol_names: unsupported `&str` constant: {:?}", ct); + } } - self.push("_"); } - _ => { - bug!("symbol_names: unsupported `&str` constant: {:?}", ct); + let pointee_ty = ct + .ty() + .builtin_deref(true) + .expect("tried to dereference on non-ptr type") + .ty; + let dereferenced_const = + self.tcx.mk_const(ty::ConstS { val: ct.val(), ty: pointee_ty }); + self = dereferenced_const.print(self)?; } } } - ty::Ref(_, _, mutbl) => { - self.push(match mutbl { - hir::Mutability::Not => "R", - hir::Mutability::Mut => "Q", - }); - self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?; - } - - ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => { - let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct)); + ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => { + let contents = self.tcx.destructure_const(ct); let fields = contents.fields.iter().copied(); let print_field_list = |mut this: Self| { @@ -676,7 +689,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { }; match *ct.ty().kind() { - ty::Array(..) => { + ty::Array(..) | ty::Slice(_) => { self.push("A"); self = print_field_list(self)?; } @@ -723,7 +736,6 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { _ => unreachable!(), } } - _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index c95d43b71cf..a63790b594d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -6,6 +6,7 @@ use super::*; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{Region, RegionVid, Term}; @@ -834,7 +835,16 @@ impl<'tcx> AutoTraitFinder<'tcx> { unevaluated, Some(obligation.cause.span), ) { - Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())), + Ok(Some(valtree)) => { + Ok(ty::Const::from_value(select.tcx(), valtree, c.ty())) + } + Ok(None) => { + let tcx = self.tcx; + let def_id = unevaluated.def.did; + let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit(); + + Err(ErrorHandled::Reported(reported)) + } Err(err) => Err(err), } } else { diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 6cf39be2a9d..5d08ea99ac6 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -13,9 +13,7 @@ use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ - ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar, -}; +use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::thir; use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; @@ -449,9 +447,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes.push(Node::Leaf(constant)) } &ExprKind::NonHirLiteral { lit , user_ty: _} => { - // FIXME Construct a Valtree from this ScalarInt when introducing Valtrees - let const_value = ConstValue::Scalar(Scalar::Int(lit)); - self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, const_value, node.ty))) + let val = ty::ValTree::from_scalar_int(lit); + self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) } &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 50735ef048b..7c4b5decee4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -407,7 +407,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { let pred = ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![ - obligation.with(pred.to_predicate(self.selcx.tcx())), + obligation.with(pred.to_predicate(self.selcx.tcx())) ])) } ty::PredicateKind::TypeWellFormedFromEnv(..) => { @@ -594,22 +594,24 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { let mut evaluate = |c: Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match self.selcx.infcx().const_eval_resolve( + match self.selcx.infcx().try_const_eval_resolve( obligation.param_env, unevaluated, + c.ty(), Some(obligation.cause.span), ) { - Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())), - Err(ErrorHandled::TooGeneric) => { - stalled_on.extend( - unevaluated - .substs - .iter() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg), - ); - Err(ErrorHandled::TooGeneric) - } - Err(err) => Err(err), + Ok(val) => Ok(val), + Err(e) => match e { + ErrorHandled::TooGeneric => { + stalled_on.extend( + unevaluated.substs.iter().filter_map( + TyOrConstInferVar::maybe_from_generic_arg, + ), + ); + Err(ErrorHandled::TooGeneric) + } + _ => Err(e), + }, } } else { Ok(c) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 565f3f509db..a72f90746ed 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -618,11 +618,14 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement { constant } else { let constant = constant.super_fold_with(self); + debug!(?constant); + debug!("self.param_env: {:?}", self.param_env); constant.eval(self.selcx.tcx(), self.param_env) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b00f8fe73a1..b80a27eb07d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -100,7 +100,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { } } -/// Visitor to find the maximum escaping bound var +// Visitor to find the maximum escaping bound var struct MaxEscapingBoundVarVisitor { // The index which would count as escaping outer_index: ty::DebruijnIndex, @@ -336,12 +336,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { Ok(match constant { mir::ConstantKind::Ty(c) => { - let const_folded = c.try_fold_with(self)?; + let const_folded = c.try_super_fold_with(self)?; match const_folded.kind() { - ty::ConstKind::Value(cv) => { - // FIXME With Valtrees we need to convert `cv: ValTree` - // to a `ConstValue` here. - mir::ConstantKind::Val(cv, const_folded.ty()) + ty::ConstKind::Value(valtree) => { + let tcx = self.infcx.tcx; + let ty = const_folded.ty(); + let const_val = tcx.valtree_to_const_val((ty, valtree)); + debug!(?ty, ?valtree, ?const_val); + + mir::ConstantKind::Val(const_val, ty) } _ => mir::ConstantKind::Ty(const_folded), } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 07e7bad6cb7..a002006f0e6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -636,13 +636,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - self.infcx - .const_eval_resolve( - obligation.param_env, - unevaluated, - Some(obligation.cause.span), - ) - .map(|val| ty::Const::from_value(self.tcx(), val, c.ty())) + match self.infcx.try_const_eval_resolve( + obligation.param_env, + unevaluated, + c.ty(), + Some(obligation.cause.span), + ) { + Ok(val) => Ok(val), + Err(e) => Err(e), + } } else { Ok(c) } @@ -2576,7 +2578,11 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { } fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } + if let Some(head) = self.head { + head.depth + } else { + 0 + } } } diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index a8a324dec97..5d394ed2263 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -25,7 +25,6 @@ pub(crate) fn provide(p: &mut Providers) { }; } -#[instrument(level = "debug", skip(tcx))] fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>( tcx: TyCtxt<'tcx>, goal: ParamEnvAnd<'tcx, T>, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 7c89ce125e0..552db5406df 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -112,7 +112,6 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } } -#[instrument(level = "debug", skip(tcx))] fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, @@ -141,7 +140,6 @@ fn resolve_instance_of_const_arg<'tcx>( ) } -#[instrument(level = "debug", skip(tcx))] fn inner_resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>, |
