Auto merge of #74949 - oli-obk:validate_const_eval_raw, r=RalfJung
Validate constants during `const_eval_raw` This PR implements the groundwork for https://github.com/rust-lang/rust/issues/72396 * constants are now validated during `const_eval_raw` * to prevent cycle errors, we do not validate references to statics anymore beyond the fact that they are not dangling * the `const_eval` query ICEs if used on `static` items * as a side effect promoteds are now evaluated to `ConstValue::Scalar` again (since they are just a reference to the actual promoted allocation in most cases).
This commit is contained in:
commit
5e449b9adf
52 changed files with 347 additions and 420 deletions
|
@ -1,4 +1,4 @@
|
|||
use super::{AllocId, Pointer, RawConst, Scalar};
|
||||
use super::{AllocId, ConstAlloc, Pointer, Scalar};
|
||||
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
|
||||
|
@ -27,8 +27,8 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
ErrorHandled,
|
||||
}
|
||||
|
||||
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
||||
pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
|
||||
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
|
||||
|
|
|
@ -118,12 +118,12 @@ use crate::ty::subst::GenericArgKind;
|
|||
use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||
|
||||
pub use self::error::{
|
||||
struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError,
|
||||
InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo,
|
||||
UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
||||
struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
|
||||
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
|
||||
ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
||||
};
|
||||
|
||||
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
|
||||
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
|
||||
|
||||
pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{ConstEvalResult, ErrorHandled, GlobalId};
|
||||
use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
|
||||
|
||||
use crate::mir;
|
||||
use crate::ty::subst::{InternalSubsts, SubstsRef};
|
||||
|
@ -10,7 +10,7 @@ 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.
|
||||
pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
|
||||
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
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
|
@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
substs: SubstsRef<'tcx>,
|
||||
promoted: Option<mir::Promoted>,
|
||||
span: Option<Span>,
|
||||
) -> ConstEvalResult<'tcx> {
|
||||
) -> EvalToConstValueResult<'tcx> {
|
||||
match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) {
|
||||
Ok(Some(instance)) => {
|
||||
let cid = GlobalId { instance, promoted };
|
||||
|
@ -54,7 +54,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> ConstEvalResult<'tcx> {
|
||||
) -> EvalToConstValueResult<'tcx> {
|
||||
self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
|
||||
}
|
||||
|
||||
|
@ -64,14 +64,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> ConstEvalResult<'tcx> {
|
||||
) -> EvalToConstValueResult<'tcx> {
|
||||
// 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(¶m_env.and(cid));
|
||||
if let Some(span) = span {
|
||||
self.at(span).const_eval_validated(inputs)
|
||||
self.at(span).eval_to_const_value_raw(inputs)
|
||||
} else {
|
||||
self.const_eval_validated(inputs)
|
||||
self.eval_to_const_value_raw(inputs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<&'tcx mir::Allocation, ErrorHandled> {
|
||||
trace!("eval_to_allocation: Need to compute {:?}", gid);
|
||||
let raw_const = self.const_eval_raw(param_env.and(gid))?;
|
||||
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
|
||||
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ use crate::ty::{ParamEnv, Ty, TyCtxt};
|
|||
|
||||
use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
|
||||
|
||||
/// Represents the result of a raw const operation, pre-validation.
|
||||
/// Represents the result of const evaluation via the `eval_to_allocation` query.
|
||||
#[derive(Clone, HashStable)]
|
||||
pub struct RawConst<'tcx> {
|
||||
pub struct ConstAlloc<'tcx> {
|
||||
// the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
|
||||
// (so you can use `AllocMap::unwrap_memory`).
|
||||
pub alloc_id: AllocId,
|
||||
|
|
|
@ -707,32 +707,27 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
Other {
|
||||
/// Evaluates a constant without running sanity checks.
|
||||
/// Evaluates a constant and returns the computed allocation.
|
||||
///
|
||||
/// **Do not use this** outside const eval. Const eval uses this to break query cycles
|
||||
/// during validation. Please add a comment to every use site explaining why using
|
||||
/// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
|
||||
/// form to be used outside of const eval.
|
||||
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> ConstEvalRawResult<'tcx> {
|
||||
/// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
|
||||
query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> EvalToAllocationRawResult<'tcx> {
|
||||
desc { |tcx|
|
||||
"const-evaluating `{}`",
|
||||
"const-evaluating + checking `{}`",
|
||||
key.value.display(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Results of evaluating const items or constants embedded in
|
||||
/// other items (such as enum variant explicit discriminants).
|
||||
///
|
||||
/// In contrast to `const_eval_raw` this performs some validation on the constant, and
|
||||
/// returns a proper constant that is usable by the rest of the compiler.
|
||||
/// Evaluates const items or anonymous constants
|
||||
/// (such as enum variant explicit discriminants or array lengths)
|
||||
/// into a representation suitable for the type system and const generics.
|
||||
///
|
||||
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
|
||||
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
|
||||
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> ConstEvalResult<'tcx> {
|
||||
query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> EvalToConstValueResult<'tcx> {
|
||||
desc { |tcx|
|
||||
"const-evaluating + checking `{}`",
|
||||
"simplifying constant for the type system `{}`",
|
||||
key.value.display(tcx)
|
||||
}
|
||||
cache_on_disk_if(_, opt_result) {
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife
|
|||
use crate::middle::stability::{self, DeprecationEntry};
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::GlobalId;
|
||||
use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue};
|
||||
use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
|
||||
use crate::mir::interpret::{LitToConstError, LitToConstInput};
|
||||
use crate::mir::mono::CodegenUnit;
|
||||
use crate::traits::query::{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue