Heap allocations in constants
See original GitHub issueProposal
Summary and problem statement
Support allocating and deallocating heap memory in constants.
Motivation, use-cases, and solution sketches
In order to totally outdo any other constant evaluators out there, it is desirable to allow things like using serde to deserialize e.g. json or toml files into constants. In order to not duplicate code between const eval and runtime, this will require types like Vec
and String
. Otherwise every type with a String
field would either need to be generic and support &str
and String
in that field, or just outright have a mirror struct for const eval. Both ways seem too restrictive and not in the spirit of “const eval that just works”.
We need to forbid constants where the final value is a non-empty buffer, because we might try to deallocate static memory if used:
const FOO: String = String::from("foo");
let x = FOO;
drop(x);
One proposed solution could be auto marker traits that decide what types constants can be. We can use ConstSafe
and ConstRefSafe
(bikeshed):
&T: ConstSafe
whereT: ConstRefSafe
&mut T: !ConstSafe
*const T: !ConstSafe
*mut T: !ConstSafe
UnsafeCell<T>: !ConstSafe
String: ConstRefSafe
*const T
isn’t ConstSafe
, since it might point to the const heap, but a null pointer is perfectly fine and can be created in constants, therefore we need another way to track if something is allocated in the heap.
We can use a const(heap)
effect to signify that the returned type contains an allocation in the heap. My current approach is an attribute: #[const_heap]
instead of modifying the syntax. The exact semantics are as follows:
- All
const fn
not marked with#[const_heap]
has a return type ofTotallyConstSafe<T>
whereT
is the annotated return type of the function.TotallyConstSafe
cannot be named. It is an invisible type that only exists in the type system.
const FOO: T
also has the typeTotallyConstSafe<T>
.- The return value of a const body coerce into
TotallyConstSafe<T>
if either:T: ConstSafe
; or- There are no calls to
#[const_heap]
functions in the body.
This would forbid const S: String = String::from("foo");
because String::from
is #[const_heap]
and String: !ConstSafe
.
const A: String = String::new(); // Ok since String::new isn't #[const_heap]
const B: String = String::from("foo"); // Not OK because of reasons above
const C: &String = &String::from("foo"); // Ok because &String is ConstSafe
const D: &str = &String::from("foo"); // Ok because &str is ConstSafe
This approach is totally backwards compatible as there are no const functions currently marked with #[const_heap]
.
Links and related work
Some text of this proposal are copied from https://github.com/rust-lang/const-eval/issues/20.
Initial people involved
- Owner, if known: @fee1-dead
- Liaison: TBD
What happens now?
This issue is part of the lang-team initiative process. Once this issue is filed, a Zulip topic will be opened for discussion, and the lang-team will review open proposals in its weekly triage meetings. You should receive feedback within a week or two.
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:13 (11 by maintainers)
Discussed in the @rust-lang/lang meeting and decided that we are going to close this issue for now. This is a deferral in the sense that we’re not opposed to the concept, but it seems like we are not ready to address this particular question right now, given the state of consteval. Thanks to @fee1-dead for raising it!
When and where will it be announced whether the meeting is scheduled for tmr or not?