Auto merge of #116564 - oli-obk:evaluated_static_in_metadata, r=RalfJung,cjgillot
Store static initializers in metadata instead of the MIR of statics. This means that adding generic statics would be even more difficult, as we can't evaluate statics from other crates anymore, but the subtle issue I have encountered make me think that having this be an explicit problem is better. The issue is that ```rust static mut FOO: &mut u32 = &mut 42; static mut BAR = unsafe { FOO }; ``` gets different allocations, instead of referring to the same one. This is also true for non-static mut, but promotion makes `static FOO: &u32 = &42;` annoying to demo. Fixes https://github.com/rust-lang/rust/issues/61345 ## Why is this being done? In order to ensure all crates see the same nested allocations (which is the last issue that needs fixing before we can stabilize [`const_mut_refs`](https://github.com/rust-lang/rust/issues/57349)), I am working on creating anonymous (from the Rust side, to LLVM it's like a regular static item) static items for the nested allocations in a static. If we evaluate the static item in a downstream crate again, we will end up duplicating its nested allocations (and in some cases, like the `match` case, even duplicate the main allocation).
This commit is contained in:
commit
6a4222b511
44 changed files with 391 additions and 193 deletions
|
@ -1,4 +1,4 @@
|
|||
use super::{AllocId, AllocRange, Pointer, Scalar};
|
||||
use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
|
||||
|
||||
use crate::error;
|
||||
use crate::mir::{ConstAlloc, ConstValue};
|
||||
|
@ -83,6 +83,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
|
|||
TrivialTypeTraversalImpls! { ErrorHandled }
|
||||
|
||||
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
||||
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
|
||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
|
||||
/// This is needed in `thir::pattern::lower_inline_const`.
|
||||
|
|
|
@ -142,11 +142,12 @@ use crate::ty::GenericArgKind;
|
|||
use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||
|
||||
pub use self::error::{
|
||||
BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult,
|
||||
EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo,
|
||||
InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind,
|
||||
ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
|
||||
UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
|
||||
BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
|
||||
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
|
||||
InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
|
||||
MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
|
||||
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
|
||||
ValidationErrorKind,
|
||||
};
|
||||
|
||||
pub use self::value::Scalar;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
|
||||
|
||||
use crate::mir;
|
||||
use crate::query::{TyCtxtAt, TyCtxtEnsure};
|
||||
use crate::query::TyCtxtEnsure;
|
||||
use crate::ty::visit::TypeVisitableExt;
|
||||
use crate::ty::GenericArgs;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
|
@ -173,44 +173,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
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(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
|
||||
self.at(DUMMY_SP).eval_static_initializer(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtAt<'tcx> {
|
||||
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
|
||||
///
|
||||
/// The span is entirely ignored here, but still helpful for better query cycle errors.
|
||||
pub fn eval_static_initializer(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
|
||||
trace!("eval_static_initializer: Need to compute {:?}", def_id);
|
||||
assert!(self.is_static(def_id));
|
||||
let instance = ty::Instance::mono(*self, def_id);
|
||||
let gid = GlobalId { instance, promoted: None };
|
||||
self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
|
||||
}
|
||||
|
||||
/// Evaluate anything constant-like, returning the allocation of the final memory.
|
||||
///
|
||||
/// The span is entirely ignored here, but still helpful for better query cycle errors.
|
||||
fn eval_to_allocation(
|
||||
self,
|
||||
gid: GlobalId<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
|
||||
trace!("eval_to_allocation: Need to compute {:?}", gid);
|
||||
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
|
||||
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
|
@ -232,15 +194,4 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
|
|||
let inputs = self.tcx.erase_regions(param_env.and(cid));
|
||||
self.eval_to_const_value_raw(inputs)
|
||||
}
|
||||
|
||||
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
|
||||
pub fn eval_static_initializer(self, def_id: DefId) {
|
||||
trace!("eval_static_initializer: Need to compute {:?}", def_id);
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
let instance = ty::Instance::mono(self.tcx, def_id);
|
||||
let gid = GlobalId { instance, promoted: None };
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
trace!("eval_to_allocation: Need to compute {:?}", gid);
|
||||
self.eval_to_allocation_raw(param_env.and(gid))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
|
||||
|
||||
use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar};
|
||||
use crate::mir::interpret::{AllocRange, Scalar};
|
||||
use crate::mir::visit::MirVisitable;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::fs;
|
|||
use std::io::{self, Write as _};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::mir::interpret::ConstAllocation;
|
||||
|
||||
use super::graphviz::write_mir_fn_graphviz;
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_middle::mir::interpret::{
|
||||
|
|
|
@ -337,6 +337,7 @@ tcx_lifetime! {
|
|||
rustc_middle::mir::ConstValue,
|
||||
rustc_middle::mir::interpret::GlobalId,
|
||||
rustc_middle::mir::interpret::LitToConstInput,
|
||||
rustc_middle::mir::interpret::EvalStaticInitializerRawResult,
|
||||
rustc_middle::traits::query::MethodAutoderefStepsResult,
|
||||
rustc_middle::traits::query::type_op::AscribeUserType,
|
||||
rustc_middle::traits::query::type_op::Eq,
|
||||
|
|
|
@ -20,7 +20,8 @@ use crate::middle::stability::{self, DeprecationEntry};
|
|||
use crate::mir;
|
||||
use crate::mir::interpret::GlobalId;
|
||||
use crate::mir::interpret::{
|
||||
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
|
||||
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
|
||||
EvalToValTreeResult,
|
||||
};
|
||||
use crate::mir::interpret::{LitToConstError, LitToConstInput};
|
||||
use crate::mir::mono::CodegenUnit;
|
||||
|
@ -1061,7 +1062,7 @@ rustc_queries! {
|
|||
|
||||
/// Evaluates a constant and returns the computed allocation.
|
||||
///
|
||||
/// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
|
||||
/// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead.
|
||||
query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> EvalToAllocationRawResult<'tcx> {
|
||||
desc { |tcx|
|
||||
|
@ -1071,6 +1072,16 @@ rustc_queries! {
|
|||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
|
||||
query eval_static_initializer(key: DefId) -> EvalStaticInitializerRawResult<'tcx> {
|
||||
desc { |tcx|
|
||||
"evaluating initializer of static `{}`",
|
||||
tcx.def_path_str(key)
|
||||
}
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
@ -126,6 +126,7 @@ parameterized_over_tcx! {
|
|||
crate::middle::exported_symbols::ExportedSymbol,
|
||||
crate::mir::Body,
|
||||
crate::mir::CoroutineLayout,
|
||||
crate::mir::interpret::ConstAllocation,
|
||||
ty::Ty,
|
||||
ty::FnSig,
|
||||
ty::GenericPredicates,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue