Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ca76eb8

Browse files
committed
Auto merge of rust-lang#116564 - oli-obk:evaluated_static_in_metadata, r=<try>
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 issues I have encountered make me think that having this be an explicit problem is better. Said issues are: ### Nested allocations of static items get duplicated which leads to issues for statics like ```rust static mut FOO: &mut u32 = &mut 42; static mut BAR = unsafe { FOO }; ``` getting 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. ### The main allocation of a static gets duplicated across crates ```rust // crate a static mut FOO: Option<u32> = Some(42); // crate b static mut BAR: &mut u32 = unsafe { match &mut a::FOO { Some(x) => x, None => panic!(), } }; ``` ## 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`](rust-lang#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).
2 parents 7ed044c + 7a7456d commit ca76eb8

File tree

16 files changed

+79
-42
lines changed

16 files changed

+79
-42
lines changed

compiler/rustc_const_eval/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ pub fn provide(providers: &mut Providers) {
4646
const_eval::provide(providers);
4747
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
4848
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
49+
providers.eval_static_initializer_raw = |tcx, def_id| {
50+
assert!(tcx.is_static(def_id.to_def_id()));
51+
let instance = ty::Instance::mono(tcx, def_id.to_def_id());
52+
let gid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
53+
let param_env = ty::ParamEnv::reveal_all();
54+
Ok(tcx.eval_to_allocation_raw(param_env.and(gid))?.alloc_id)
55+
};
4956
providers.const_caller_location = const_eval::const_caller_location;
5057
providers.eval_to_valtree = |tcx, param_env_and_value| {
5158
let (param_env, raw) = param_env_and_value.into_parts();

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ provide! { tcx, def_id, other, cdata,
242242
asyncness => { table_direct }
243243
fn_arg_names => { table }
244244
generator_kind => { table }
245+
eval_static_initializer_raw => {
246+
Ok(cdata
247+
.root
248+
.tables
249+
.eval_static_initializer_raw
250+
.get(cdata, def_id.index)
251+
.map(|lazy| lazy.decode((cdata, tcx)))
252+
.unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer_raw")))
253+
}
245254
trait_def => { table }
246255
deduced_param_attrs => { table }
247256
is_type_alias_impl_trait => {

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,11 +1034,9 @@ fn should_encode_mir(
10341034
(true, mir_opt_base)
10351035
}
10361036
// Constants
1037-
DefKind::AnonConst
1038-
| DefKind::InlineConst
1039-
| DefKind::AssocConst
1040-
| DefKind::Static(..)
1041-
| DefKind::Const => (true, false),
1037+
DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst | DefKind::Const => {
1038+
(true, false)
1039+
}
10421040
// Full-fledged functions + closures
10431041
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
10441042
let generics = tcx.generics_of(def_id);
@@ -1439,6 +1437,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14391437
let data = self.tcx.generator_kind(def_id).unwrap();
14401438
record!(self.tables.generator_kind[def_id] <- data);
14411439
}
1440+
if let DefKind::Static(_) = def_kind {
1441+
if !self.tcx.is_foreign_item(def_id) {
1442+
let data = self.tcx.eval_static_initializer_raw(def_id).unwrap();
1443+
record!(self.tables.eval_static_initializer_raw[def_id] <- data);
1444+
}
1445+
}
14421446
if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
14431447
self.encode_info_for_adt(local_id);
14441448
}

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ define_tables! {
442442
asyncness: Table<DefIndex, ty::Asyncness>,
443443
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
444444
generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
445+
eval_static_initializer_raw: Table<DefIndex, LazyValue<mir::interpret::AllocId>>,
445446
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
446447
trait_item_def_id: Table<DefIndex, RawDefId>,
447448
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
8585
TrivialTypeTraversalImpls! { ErrorHandled }
8686

8787
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
88+
pub type EvalStaticInitializerRawResult = Result<AllocId, ErrorHandled>;
8889
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
8990
/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
9091
/// This is needed in `thir::pattern::lower_inline_const`.

compiler/rustc_middle/src/mir/interpret/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ use crate::ty::GenericArgKind;
142142
use crate::ty::{self, Instance, Ty, TyCtxt};
143143

144144
pub use self::error::{
145-
struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult,
146-
EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo,
147-
InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, PointerKind,
148-
ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
149-
UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
145+
struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
146+
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
147+
InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
148+
MachineStopType, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch,
149+
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
150150
};
151151

152152
pub use self::value::Scalar;

compiler/rustc_middle/src/mir/interpret/queries.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -194,22 +194,8 @@ impl<'tcx> TyCtxtAt<'tcx> {
194194
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
195195
trace!("eval_static_initializer: Need to compute {:?}", def_id);
196196
assert!(self.is_static(def_id));
197-
let instance = ty::Instance::mono(*self, def_id);
198-
let gid = GlobalId { instance, promoted: None };
199-
self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
200-
}
201-
202-
/// Evaluate anything constant-like, returning the allocation of the final memory.
203-
///
204-
/// The span is entirely ignored here, but still helpful for better query cycle errors.
205-
fn eval_to_allocation(
206-
self,
207-
gid: GlobalId<'tcx>,
208-
param_env: ty::ParamEnv<'tcx>,
209-
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
210-
trace!("eval_to_allocation: Need to compute {:?}", gid);
211-
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
212-
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
197+
let alloc_id = self.eval_static_initializer_raw(def_id)?;
198+
Ok(self.global_alloc(alloc_id).unwrap_memory())
213199
}
214200
}
215201

@@ -237,10 +223,6 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
237223
pub fn eval_static_initializer(self, def_id: DefId) {
238224
trace!("eval_static_initializer: Need to compute {:?}", def_id);
239225
assert!(self.tcx.is_static(def_id));
240-
let instance = ty::Instance::mono(self.tcx, def_id);
241-
let gid = GlobalId { instance, promoted: None };
242-
let param_env = ty::ParamEnv::reveal_all();
243-
trace!("eval_to_allocation: Need to compute {:?}", gid);
244-
self.eval_to_allocation_raw(param_env.and(gid))
226+
self.eval_static_initializer_raw(def_id);
245227
}
246228
}

compiler/rustc_middle/src/query/erase.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ trivial! {
256256
rustc_middle::mir::interpret::AllocId,
257257
rustc_middle::mir::interpret::ErrorHandled,
258258
rustc_middle::mir::interpret::LitToConstError,
259+
rustc_middle::mir::interpret::EvalStaticInitializerRawResult,
259260
rustc_middle::thir::ExprId,
260261
rustc_middle::traits::CodegenObligationError,
261262
rustc_middle::traits::EvaluationResult,

compiler/rustc_middle/src/query/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use crate::middle::stability::{self, DeprecationEntry};
2020
use crate::mir;
2121
use crate::mir::interpret::GlobalId;
2222
use crate::mir::interpret::{
23-
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
23+
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
24+
EvalToValTreeResult,
2425
};
2526
use crate::mir::interpret::{LitToConstError, LitToConstInput};
2627
use crate::mir::mono::CodegenUnit;
@@ -1073,6 +1074,16 @@ rustc_queries! {
10731074
cache_on_disk_if { true }
10741075
}
10751076

1077+
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
1078+
query eval_static_initializer_raw(key: DefId) -> EvalStaticInitializerRawResult {
1079+
desc { |tcx|
1080+
"evaluating initializer of static `{}`",
1081+
tcx.def_path_str(key)
1082+
}
1083+
cache_on_disk_if { true }
1084+
separate_provide_extern
1085+
}
1086+
10761087
/// Evaluates const items or anonymous constants
10771088
/// (such as enum variant explicit discriminants or array lengths)
10781089
/// into a representation suitable for the type system and const generics.

compiler/rustc_middle/src/ty/parameterized.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ trivially_parameterized_over_tcx! {
6161
crate::middle::exported_symbols::SymbolExportInfo,
6262
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
6363
crate::mir::ConstQualifs,
64+
crate::mir::interpret::AllocId,
6465
ty::AssocItemContainer,
6566
ty::Asyncness,
6667
ty::DeducedParamAttrs,

0 commit comments

Comments
 (0)