mirror of https://github.com/rust-lang/rfcs.git
93 lines
3.1 KiB
Markdown
93 lines
3.1 KiB
Markdown
- Start Date: 2014-05-07
|
|
- RFC PR: [rust-lang/rfcs#71](https://github.com/rust-lang/rfcs/pull/71)
|
|
- Rust Issue: [rust-lang/rust#14181](https://github.com/rust-lang/rust/issues/14181)
|
|
|
|
# Summary
|
|
|
|
Allow block expressions in statics, as long as they only contain items
|
|
and a trailing const expression.
|
|
|
|
Example:
|
|
|
|
```rust
|
|
static FOO: uint = { 100 };
|
|
static BAR: fn() -> int = {
|
|
fn hidden() -> int {
|
|
42
|
|
}
|
|
hidden
|
|
};
|
|
```
|
|
|
|
# Motivation
|
|
|
|
This change allows defining items as part of a const expression,
|
|
and evaluating to a value using them.
|
|
This is mainly useful for macros, as it allows hiding complex machinery behind something
|
|
that expands to a value, but also enables using `unsafe {}` blocks in a static initializer.
|
|
|
|
Real life examples include the `regex!` macro, which currently expands to a block containing a
|
|
function definition and a value, and would be usable in a static with this.
|
|
|
|
Another example would be to expose a static reference to a fixed memory address by
|
|
dereferencing a raw pointer in a const expr, which is useful in
|
|
embedded and kernel, but requires a `unsafe` block to do.
|
|
|
|
The outcome of this is that one additional expression type becomes valid as a const
|
|
expression, with semantics that are a strict subset of its equivalent in a function.
|
|
|
|
# Drawbacks
|
|
|
|
Block expressions in a function are usually just used to run arbitrary code before
|
|
evaluating to a value. Allowing them in statics without allowing code
|
|
execution might be confusing.
|
|
|
|
# Detailed design
|
|
|
|
A branch implementing this feature can be found at
|
|
https://github.com/Kimundi/rust/tree/const_block.
|
|
|
|
It mainly involves the following changes:
|
|
|
|
- const check now allows block expressions in statics:
|
|
- All statements that are not item declarations lead to an compile error.
|
|
- trans and const eval are made aware of block expressions:
|
|
- A trailing expression gets evaluated as a constant.
|
|
- A missing trailing expressions is treated as a unit value.
|
|
- trans is made to recurse into static expressions to generate possible items.
|
|
|
|
Things like privacy/reachability of definitions inside a static block
|
|
are already handled more generally at other places, as the situation is
|
|
very similar to a regular function.
|
|
|
|
The branch also includes tests that show how this feature works in practice.
|
|
|
|
# Alternatives
|
|
|
|
Because this feature is a straight forward extension of the valid const expressions,
|
|
it already causes a very minimal impact on the language, with most alternative ways
|
|
of enabling the same benefits being more complex.
|
|
|
|
For example, a expression AST node that can include items but is only usable from procedural macros
|
|
could be added.
|
|
|
|
Not having this feature would not prevent anything interesting from getting implemented,
|
|
but it would lead to less nice looking solutions.
|
|
|
|
For example, a comparison between static-supporting `regex!` with and without this feature:
|
|
|
|
```rust
|
|
// With this feature, you can just initialize a static:
|
|
static R: Regex = regex!("[0-9]");
|
|
|
|
// Without it, the static needs to be generated by the
|
|
// macro itself, alongside all generated items:
|
|
regex! {
|
|
static R = "[0-9]";
|
|
}
|
|
```
|
|
|
|
# Unresolved questions
|
|
|
|
None so far.
|