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/rustc_mir_build/src | |
| 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/rustc_mir_build/src')
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_constant.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/mod.rs | 118 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/constant.rs | 75 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 7 |
5 files changed, 169 insertions, 93 deletions
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() } |
