1
1
# Const promotion
2
2
3
- " Promotion" is a mechanism that affects code like ` &3 ` : Instead of putting it on
4
- the stack, the ` 3 ` is allocated in global static memory and a reference with
5
- lifetime ` 'static ` is provided. This is essentially an automatic transformation
6
- turning ` &EXPR ` into ` { const _PROMOTED = &EXPR; EXPR } ` , but only if ` EXPR `
7
- qualifies.
3
+ [ "(Implicit) Promotion"] [ rfc ] is a mechanism that affects code like ` &3 ` :
4
+ Instead of putting it on the stack, the ` 3 ` is allocated in global static memory
5
+ and a reference with lifetime ` 'static ` is provided. This is essentially an
6
+ automatic transformation turning ` &EXPR ` into `{ const _ PROMOTED = &EXPR; EXPR
7
+ } ` , but only if ` EXPR` qualifies.
8
8
9
9
Note that promotion happens on the MIR, not on surface-level syntax. This is
10
10
relevant when discussing e.g. handling of panics caused by overflowing
11
11
arithmetic.
12
12
13
+ 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* .
14
+ Thus, if CTFE fails but the code would have worked fine at run-time, we broke the user's code for no good reason.
15
+ That's why we have to be very conservative with what can and cannot be promoted.
16
+
17
+ [ rfc ] : https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md
18
+
13
19
## Rules
14
20
15
21
### 1. Panics
16
22
17
23
Promotion is not allowed to throw away side effects. This includes panicking.
18
24
Let us look at what happens when we promote ` &(0_usize - 1) ` in a debug build:
19
25
We have to avoid erroring at compile-time, because that would be promotion
20
- breaking compilation (the code would have compiled just fine if we hadn't
21
- promoted), but we must be sure to error correctly at run-time. In the MIR, this
22
- looks roughly like
26
+ breaking compilation, but we must be sure to error correctly at run-time. In
27
+ the MIR, this looks roughly like
23
28
24
29
```
25
30
_tmp1 = CheckedSub (const 0usize) (const 1usize)
@@ -89,18 +94,12 @@ but to abort compilation of a program that would have compiled fine if we would
89
94
not have decided to promote. It is the responsibility of ` foo ` to not fail this
90
95
way when working with const-safe arguments.
91
96
92
- ### 3. Constraints on constants
93
-
94
- All the [ extra restrictions for constants] ( const.md ) beyond const safety also
95
- apply to promoteds, for the same reason: Evaluating the expression at
96
- compile-time instead of run-time should not alter program behavior.
97
-
98
- ### 4. Drop
97
+ ### 3. Drop
99
98
100
- Expressions containing "needs drop" types
101
- can never be promoted. If such an expression were promoted, the ` Drop ` impl would
102
- never get called on the value, even though the user did not explicitly request such
103
- behavior by using an explicit ` const ` or ` static ` item.
99
+ Expressions returning "needs drop" types can never be promoted. If such an
100
+ expression were promoted, the ` Drop ` impl would never get called on the value,
101
+ even though the user did not explicitly request such behavior by using an
102
+ explicit ` const ` or ` static ` item.
104
103
105
104
As expression promotion is essentially the silent insertion of a ` static ` item, and
106
105
` static ` items never have their ` Drop ` impl called, the ` Drop ` impl of the promoted
@@ -111,6 +110,38 @@ it is unlikely to be the desired behavior in most cases and very likey to be con
111
110
to the user. If such behavior is desired, the user can still use an explicit ` static `
112
111
or ` const ` item and refer to that.
113
112
113
+ ## ` & ` in ` const ` and ` static `
114
+
115
+ Promotion is also responsible for making code like this work:
116
+
117
+ ``` rust
118
+ const FOO : & 'static i32 = {
119
+ let x = & 13 ;
120
+ x
121
+ };
122
+ ```
123
+
124
+ However, since this is in explicit const context, we could be less strict about
125
+ promotion in this situation.
126
+
127
+ Promotion is * not* involved in something like this:
128
+
129
+ ``` rust
130
+ #![feature(const_vec_new)]
131
+ const EMPTY_BYTES : & Vec <u8 > = & Vec :: new ();
132
+
133
+ const NESTED : & 'static Vec <u8 > = {
134
+ // This does not work when we have an inner scope:
135
+ let x = & Vec :: new (); // ~ ERROR: temporary value dropped while borrowed
136
+ x
137
+ };
138
+ ```
139
+
140
+ In ` EMPTY_BYTES ` , the reference obtains the lifetime of the "enclosing scope",
141
+ similar to how ` let x = &mut x; ` creates a reference whose lifetime lasts for
142
+ the enclosing scope. This is decided during MIR building already, and does not
143
+ involve promotion.
144
+
114
145
## Open questions
115
146
116
147
* There is a fourth kind of CTFE failure -- resource exhaustion. What do we do
0 commit comments