Merge remote-tracking branch 'kimundi/const-block-expr'

This commit is contained in:
Alex Crichton 2014-05-13 13:21:03 -07:00
commit 0f3603d33c
1 changed files with 92 additions and 0 deletions

View File

@ -0,0 +1,92 @@
- Start Date: 2014-05-07
- RFC PR #: (leave this empty)
- Rust Issue #: (leave this empty)
# 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.