Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ca76eb8

Browse files
committedOct 9, 2023
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

16 files changed

+79
-42
lines changed
 

‎compiler/rustc_const_eval/src/lib.rs

+7
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

+9
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

+9-5
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

+1
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

+1
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

+5-5
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

+3-21
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

+1
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

+12-1
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

+1
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,

‎tests/ui/consts/recursive-zst-static.default.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
error[E0391]: cycle detected when const-evaluating + checking `FOO`
1+
error[E0391]: cycle detected when evaluating initializer of static `FOO`
22
--> $DIR/recursive-zst-static.rs:10:1
33
|
44
LL | static FOO: () = FOO;
55
| ^^^^^^^^^^^^^^
66
|
7+
note: ...which requires const-evaluating + checking `FOO`...
8+
--> $DIR/recursive-zst-static.rs:10:1
9+
|
10+
LL | static FOO: () = FOO;
11+
| ^^^^^^^^^^^^^^
712
note: ...which requires const-evaluating + checking `FOO`...
813
--> $DIR/recursive-zst-static.rs:10:18
914
|
1015
LL | static FOO: () = FOO;
1116
| ^^^
12-
= note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
17+
= note: ...which again requires evaluating initializer of static `FOO`, completing the cycle
1318
note: cycle used when linting top-level module
1419
--> $DIR/recursive-zst-static.rs:10:1
1520
|

‎tests/ui/consts/recursive-zst-static.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// can depend on this fact and will thus do unsound things when it is violated.
88
// See https://github.com/rust-lang/rust/issues/71078 for more details.
99

10-
static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO`
10+
static FOO: () = FOO; //~ cycle detected when evaluating initializer of static `FOO`
1111

1212
fn main() {
1313
FOO

‎tests/ui/consts/recursive-zst-static.unleash.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
error[E0391]: cycle detected when const-evaluating + checking `FOO`
1+
error[E0391]: cycle detected when evaluating initializer of static `FOO`
22
--> $DIR/recursive-zst-static.rs:10:1
33
|
44
LL | static FOO: () = FOO;
55
| ^^^^^^^^^^^^^^
66
|
7+
note: ...which requires const-evaluating + checking `FOO`...
8+
--> $DIR/recursive-zst-static.rs:10:1
9+
|
10+
LL | static FOO: () = FOO;
11+
| ^^^^^^^^^^^^^^
712
note: ...which requires const-evaluating + checking `FOO`...
813
--> $DIR/recursive-zst-static.rs:10:18
914
|
1015
LL | static FOO: () = FOO;
1116
| ^^^
12-
= note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
17+
= note: ...which again requires evaluating initializer of static `FOO`, completing the cycle
1318
note: cycle used when linting top-level module
1419
--> $DIR/recursive-zst-static.rs:10:1
1520
|

‎tests/ui/consts/write-to-static-mut-in-static.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,23 @@ error[E0080]: could not evaluate static initializer
44
LL | pub static mut B: () = unsafe { A = 1; };
55
| ^^^^^ modifying a static's initial value from another static's initializer
66

7-
error[E0391]: cycle detected when const-evaluating + checking `C`
7+
error[E0391]: cycle detected when evaluating initializer of static `C`
88
--> $DIR/write-to-static-mut-in-static.rs:5:1
99
|
1010
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
1111
| ^^^^^^^^^^^^^^^^^^^^^
1212
|
13+
note: ...which requires const-evaluating + checking `C`...
14+
--> $DIR/write-to-static-mut-in-static.rs:5:1
15+
|
16+
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
17+
| ^^^^^^^^^^^^^^^^^^^^^
1318
note: ...which requires const-evaluating + checking `C`...
1419
--> $DIR/write-to-static-mut-in-static.rs:5:34
1520
|
1621
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
1722
| ^^^^^
18-
= note: ...which again requires const-evaluating + checking `C`, completing the cycle
23+
= note: ...which again requires evaluating initializer of static `C`, completing the cycle
1924
note: cycle used when linting top-level module
2025
--> $DIR/write-to-static-mut-in-static.rs:1:1
2126
|
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
pub static FOO: u32 = FOO;
2-
//~^ ERROR cycle detected when const-evaluating + checking `FOO`
2+
//~^ ERROR cycle detected when evaluating initializer of static `FOO`
33

44
fn main() {}

‎tests/ui/recursion/recursive-static-definition.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
error[E0391]: cycle detected when const-evaluating + checking `FOO`
1+
error[E0391]: cycle detected when evaluating initializer of static `FOO`
22
--> $DIR/recursive-static-definition.rs:1:1
33
|
44
LL | pub static FOO: u32 = FOO;
55
| ^^^^^^^^^^^^^^^^^^^
66
|
7+
note: ...which requires const-evaluating + checking `FOO`...
8+
--> $DIR/recursive-static-definition.rs:1:1
9+
|
10+
LL | pub static FOO: u32 = FOO;
11+
| ^^^^^^^^^^^^^^^^^^^
712
note: ...which requires const-evaluating + checking `FOO`...
813
--> $DIR/recursive-static-definition.rs:1:23
914
|
1015
LL | pub static FOO: u32 = FOO;
1116
| ^^^
12-
= note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
17+
= note: ...which again requires evaluating initializer of static `FOO`, completing the cycle
1318
note: cycle used when linting top-level module
1419
--> $DIR/recursive-static-definition.rs:1:1
1520
|

0 commit comments

Comments
 (0)
Please sign in to comment.