Skip to content

Commit 9d36e9a

Browse files
committed
update promotion docs
1 parent 0d168d0 commit 9d36e9a

File tree

1 file changed

+32
-35
lines changed

1 file changed

+32
-35
lines changed

promotion.md

+32-35
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Const promotion
22

3-
"Promotion" is the act of guaranteeing that code *not* written in an (explicit)
4-
const context will be run at compile-time. Explicit const contexts include the
5-
initializer of a `const` or `static`, or an array length expression.
3+
"Promotion" is the act of splicing a part of a MIR computation out into a
4+
separate self-contained MIR body which is evaluated at compile-time like a
5+
constant.
66

77
## Promotion contexts
88

@@ -44,41 +44,41 @@ attribute, introduced in
4444
specify these parameters and (aggressively, see below) try to promote the
4545
corresponding arguments.
4646

47-
### Implicit and explicit contexts
47+
## Implicit and explicit promotion
4848

4949
On top of what applies to [consts](const.md), promoteds suffer from the additional issue that *the user did not ask for them to be evaluated at compile-time*.
5050
Thus, if CTFE fails but the code would have worked fine at run-time, we broke the user's code for no good reason.
5151
Even if we are sure we found an error in the user's code, we are only allowed to [emit a warning, not a hard error][warn-rfc].
52-
That's why we have to be very conservative with what can and cannot be promoted.
52+
We call this *implicit* promotion, and we have to be very conservative with what can and cannot be implicitly promoted.
5353

54-
For example, users might be surprised to learn that whenever they take a
55-
reference to a temporary, that temporary may be promoted away and never
56-
actually put on the stack. In this way, lifetime extension is an "implicit
57-
promotion context": the user did not ask for the value to be promoted.
54+
CTFE of implicitly promoted code must never fail to evaluate except if the
55+
run-time code also would have failed. This means we cannot permit calling
56+
arbitrary `const fn`, as discussed in detail in
57+
[rust-lang/const-eval#19](https://github.com/rust-lang/const-eval/issues/19).
58+
Thus, only functions marked `#[rustc_promotable]` are implicitly promotable (see
59+
below).
5860

5961
On the other hand, when a user passes an expression to a function with
60-
`#[rustc_args_required_const]`, the only way for this code to compile is to promote it.
61-
In that sense, the user is explicitly asking for that expression
62-
to be evaluated at compile-time even though they have not written it in a
63-
`const` declaration. We call this an "explicit promotion context".
62+
`#[rustc_args_required_const]`, the only way for this code to compile is to
63+
promote it. In that sense, the user is explicitly asking for that expression to
64+
be evaluated at compile-time even though they have not written it in a `const`
65+
declaration. We can thus be less conservative. This is called *explicit*
66+
promotion.
6467

65-
Currently, non-`Copy` array initialization is treated as an implicit context,
66-
because the code could compile even without promotion (namely, if the result
67-
type is `Copy`).
68+
Currently, the following are considered explicit promotion contexts:
69+
* `#[rustc_args_required_const]` arguments
70+
* the bodies of `const` and `static` items and array lengths
6871

69-
CTFE of implicitly promoted code must never fail to evaluate except of the
70-
run-time code also would have failed. This means we cannot permit calling
71-
arbitrary `const fn`, as we cannot predict if they are going to perform an
72-
["unconst" operation](const_safety.md). Thus, only functions marked
73-
`#[rustc_promotable]` are implicitly promotable (see below). See
74-
[rust-lang/const-eval#19](https://github.com/rust-lang/const-eval/issues/19) for
75-
a thorough discussion of this. At present, this is the only difference between
76-
implicit and explicit contexts. The requirements for promotion in an implicit
77-
context are a superset of the ones in an explicit context.
72+
Everything else is an implicit promotion context, including `const fn` bodies and non-`Copy` array initializers.
73+
74+
In an explicit promotion context, we promote every closed expression (i.e.,
75+
expressions that do not depend on other variables) of reference type, subject to
76+
the usual restrictions of [consts](const.md). This means that interior
77+
mutability and values that need dropping are not promoted.
7878

7979
[warn-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
8080

81-
### Promotion contexts inside `const` and `static`
81+
## Promotion inside `const` and `static`
8282

8383
Lifetime extension is also responsible for making code like this work:
8484

@@ -89,14 +89,11 @@ const FOO: &'static i32 = {
8989
};
9090
```
9191

92-
We defined above that promotion guarantees that code in a non-const context
93-
will be executed at compile-time. The above example illustrates that lifetime
94-
extension and non-`Copy` array initialization are useful features *inside*
95-
`const`s and `static`s as well. Strictly speaking, the transformation used to
96-
enable these features inside a const-context is not promotion; no `promoted`s
97-
are created in the MIR. However the same rules for promotability are used with
98-
one modification: Because the user has already requested that this code run at
99-
compile time, all contexts are treated as explicit.
92+
Like in run-time code, a part of the MIR (the one computing `13`) is spliced
93+
into a separate MIR body, and evaluated like a separate constant. In the case
94+
of `const` and `static` initializers, this does not affect how the code is
95+
evaluated (everything happens at compile-time), but it still affects the
96+
lifetimes.
10097

10198
Notice that some code involving `&` *looks* like it relies on lifetime
10299
extension but actually does not:
@@ -105,7 +102,7 @@ extension but actually does not:
105102
const EMPTY_BYTES: &Vec<u8> = &Vec::new(); // Ok without lifetime extension
106103
```
107104

108-
As we have seen above, `Vec::new()` does not get promoted. And yet this
105+
`Vec::new()` cannot get promoted because it needs dropping. And yet this
109106
compiles. Why that? The reason is that the reference obtains the lifetime of
110107
the "enclosing scope", similar to how `let x = &mut x;` creates a reference
111108
whose lifetime lasts for the enclosing scope. This is decided during MIR

0 commit comments

Comments
 (0)