From 96b36d6eb21daaca2c2d04fd8d7c27bef5eb90c6 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 12 Apr 2022 18:14:28 +0200 Subject: use GlobalId in eval_to_valtree query and introduce query for valtree_to_const_val --- compiler/rustc_middle/src/mir/interpret/error.rs | 3 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 6 +-- compiler/rustc_middle/src/mir/interpret/queries.rs | 13 +++++- compiler/rustc_middle/src/mir/mod.rs | 54 +++++++++++++++++++++- compiler/rustc_middle/src/mir/query.rs | 11 ++++- compiler/rustc_middle/src/query/mod.rs | 35 ++++++++++---- compiler/rustc_middle/src/thir.rs | 6 +-- compiler/rustc_middle/src/ty/query.rs | 6 ++- compiler/rustc_middle/src/ty/util.rs | 12 +++-- 9 files changed, 119 insertions(+), 27 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9afe9523fca..bb6b10149ab 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use super::{AllocId, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; +use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -35,6 +35,7 @@ TrivialTypeFoldableAndLiftImpls! { pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; +pub type EvalToValTreeResult<'tcx> = Result>, ErrorHandled>; pub fn struct_error<'tcx>( tcx: TyCtxtAt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d8cba39c6d9..0fa4b10399a 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -119,9 +119,9 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, - InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, - ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, - UnsupportedOpInfo, + EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, + MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, + UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 7e5989b4112..5fb8e911124 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -110,11 +110,22 @@ impl<'tcx> TyCtxt<'tcx> { Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } - /// Destructure a constant ADT or array into its variant index and its field values. + /// 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() } + + /// Destructure a mir 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_mir_constant( + self, + param_env: ty::ParamEnv<'tcx>, + constant: mir::ConstantKind<'tcx>, + ) -> mir::DestructuredMirConstant<'tcx> { + self.try_destructure_mir_constant(param_env.and(constant)).unwrap() + } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index af18adac2ff..e6304b82094 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [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, Scalar}; +use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -3078,6 +3078,58 @@ impl<'tcx> ConstantKind<'tcx> { Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) } + #[instrument(skip(tcx), level = "debug")] + pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, + _ => span_bug!( + tcx.def_span(def_id.to_def_id()), + "from_inline_const can only process anonymous constants" + ), + }; + let expr = &tcx.hir().body(body_id).value; + let ty = tcx.typeck(def_id).node_type(hir_id); + + let lit_input = match expr.kind { + hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { + hir::ExprKind::Lit(ref lit) => { + Some(LitToConstInput { lit: &lit.node, ty, neg: true }) + } + _ => None, + }, + _ => None, + }; + if let Some(lit_input) = lit_input { + // If an error occurred, ignore that it's a literal and leave reporting the error up to + // mir. + match tcx.at(expr.span).lit_to_mir_constant(lit_input) { + Ok(c) => return c, + Err(_) => {} + } + } + + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); + let parent_substs = + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); + let substs = + ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) + .substs; + let uneval_const = tcx.mk_const(ty::ConstS { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id).to_global(), + substs, + promoted: None, + }), + ty, + }); + debug!(?uneval_const); + debug_assert!(!uneval_const.has_free_regions()); + + Self::Ty(uneval_const) + } + #[instrument(skip(tcx), level = "debug")] fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 4d4eed179ca..7f7b8bdfc14 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::{Body, Promoted}; +use crate::mir::{self, Body, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::vec_map::VecMap; @@ -413,13 +413,20 @@ pub enum ClosureOutlivesSubject<'tcx> { Region(ty::RegionVid), } -/// The constituent parts of an ADT or array. +/// The constituent parts of a type level constant of kind ADT or array. #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [ty::Const<'tcx>], } +/// The constituent parts of a mir constant of kind ADT or array. +#[derive(Copy, Clone, Debug, HashStable)] +pub struct DestructuredMirConstant<'tcx> { + pub variant: Option, + pub fields: &'tcx [mir::ConstantKind<'tcx>], +} + /// Coverage information summarized from a MIR if instrumented for source code coverage (see /// compiler option `-Cinstrument-coverage`). This information is generated by the /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6d7ec247d04..c2b974f85cc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -946,12 +946,12 @@ rustc_queries! { cache_on_disk_if { true } } - /// Convert an evaluated constant to a type level constant or + /// Evaluate a constant and convert it to a type level constant or /// return `None` if that is not possible. - query const_to_valtree( - key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> - ) -> Option> { - desc { "destructure constant" } + query eval_to_valtree( + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>> + ) -> EvalToValTreeResult<'tcx> { + desc { "evaluate type-level constant" } remap_env_constness } @@ -964,10 +964,14 @@ 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> { - desc { "destructure constant" } + query try_destructure_const(key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>) -> Option> { + desc { "destructure type level constant"} + } + + /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index + /// and its field values. + query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option> { + desc { "destructure mir constant"} remap_env_constness } @@ -980,6 +984,15 @@ rustc_queries! { 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> { + desc { "deref constant" } + remap_env_constness + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } @@ -991,6 +1004,10 @@ rustc_queries! { desc { "converting literal to const" } } + query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result, LitToConstError> { + desc { "converting literal to mir constant" } + } + query check_match(key: DefId) { desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index fdf5ecfdaf7..26e070af764 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -662,7 +662,7 @@ pub enum PatKind<'tcx> { /// * Opaque constants, that must not be matched structurally. So anything that does not derive /// `PartialEq` and `Eq`. Constant { - value: ty::Const<'tcx>, + value: mir::ConstantKind<'tcx>, }, Range(PatRange<'tcx>), @@ -692,8 +692,8 @@ pub enum PatKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: ty::Const<'tcx>, - pub hi: ty::Const<'tcx>, + pub lo: mir::ConstantKind<'tcx>, + pub hi: mir::ConstantKind<'tcx>, pub end: RangeEnd, } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index fb937ded65a..0398a83e220 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -13,8 +13,10 @@ use crate::middle::resolve_lifetime::{ use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; -use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; +use crate::mir::interpret::{ + ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, +}; +use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::thir; use crate::traits::query::{ diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 10520670069..cd099279fc7 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,7 +6,7 @@ use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::{ - self, Const, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, + self, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, TypeFoldable, }; use rustc_apfloat::Float as _; @@ -689,7 +689,7 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { impl<'tcx> Ty<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -704,12 +704,13 @@ impl<'tcx> Ty<'tcx> { }), _ => None, }; - val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -723,7 +724,8 @@ impl<'tcx> Ty<'tcx> { }), _ => None, }; - val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Checks whether values of this type `T` are *moved* or *copied* -- cgit 1.4.1-3-g733a5