1
1
# Const promotion
2
2
3
- [ "(Implicit) Promotion"] [ promotion-rfc ] is a mechanism that affects code like ` &3 ` :
3
+ "Promotion" is the act of guaranteeing that code not written in a const context
4
+ (e.g. initalizer of a ` const ` or ` static ` , or an array length expression) will
5
+ be run at compile-time.
6
+
7
+ ## Promotion contexts
8
+
9
+ There are a few different contexts where promotion is beneficial.
10
+
11
+ ### Lifetime extension
12
+
13
+ "Lifetime extension" is a mechanism that affects code like ` &3 ` :
4
14
Instead of putting it on the stack, the ` 3 ` is allocated in global static memory
5
15
and a reference with lifetime ` 'static ` is provided. This is essentially an
6
16
automatic transformation turning ` &EXPR ` into
@@ -10,15 +20,111 @@ Note that promotion happens on the MIR, not on surface-level syntax. This is
10
20
relevant when discussing e.g. handling of panics caused by overflowing
11
21
arithmetic.
12
22
23
+ Lifetime extension is described in [ RFC 1414] [ promotion-rfc ] . The RFC uses the
24
+ word "promotion" to refer exclusively to lifetime extension, since this was the
25
+ first context where promotion was done.
26
+
27
+ [ promotion-rfc ] : https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md
28
+
29
+ ### Non-` Copy ` array initialization
30
+
31
+ Another promotion context was introduced in [ RFC
32
+ 2203] ( https://github.com/rust-rfcs/const-eval/blob/master/const.md ) . In this
33
+ case, we try to promote the initializer in expressions like ` [Vec::new(); 32] ` ,
34
+ which allows non-` Copy ` types to be used as array initializers.
35
+
36
+ ### ` #[rustc_args_required_const(...)] `
37
+
38
+ Additionally, some platform intrinsics require certain operations to be
39
+ immediates (known at compile-time). We use the ` #[rustc_args_required_const] `
40
+ attribute, introduced in
41
+ [ rust-lang/rust #48018 ] ( https://github.com/rust-lang/rust/pull/48018 ) , to
42
+ specify these parameters and (aggressively, see below) try to promote the
43
+ corresponding arguments.
44
+
45
+ ### Implicit and explicit contexts
46
+
13
47
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
48
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
49
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 ] .
16
50
That's why we have to be very conservative with what can and cannot be promoted.
17
51
18
- [ promotion-rfc ] : https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md
52
+ For example, users might be surprised to learn that whenever they take a
53
+ reference to a temporary, that temporary may be promoted away and never
54
+ actually put on the stack. In this way, lifetime extension is an "implicit
55
+ promotion context": the user did not ask for the value to be promoted.
56
+
57
+ On the other hand, when a user passes an expression to a function with
58
+ ` #[rustc_args_required_const] ` , they are explicitly asking for that expression
59
+ to be evaluated at compile-time even though they have not written it in a
60
+ ` const ` declaration. We call this an "explicit promotion context".
61
+
62
+ Currently, non-` Copy ` array initialization is treated as an implicit context.
63
+
64
+ The distinction between these two determines whether calls to arbitrary `const
65
+ fn` s (those without ` #[ rustc_promotable] `) are promotable (see below). See
66
+ [ rust-rfcs/const-eval #19 ] ( https://github.com/rust-rfcs/const-eval/issues/19 )
67
+ for a thorough discussion of this. At present, this is the only difference
68
+ between implicit and explicit contexts. The requirements for promotion in an
69
+ implicit context are a superset of the ones in an explicit context.
70
+
19
71
[ warn-rfc ] : https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
20
72
21
- ## Rules
73
+ ### Lifetime extension in ` const ` and ` static `
74
+
75
+ We defined above that promotion guarantees that code in a non-const context
76
+ will be executed at compile-time. However, lifetime extension is useful
77
+ * inside* ` const ` s and ` static ` s as well (unlike the other promotion contexts).
78
+ Strictly speaking, lifetime extension in a const-context is not promotion; it
79
+ does not create ` promoted ` s in the MIR. However the same rules for
80
+ promotability apply inside a const-context as outside.
81
+
82
+ It's an open question whether lifetime extension within a ` const ` or ` static `
83
+ should be an implicit or explicit context. Currently it is treated as an
84
+ implicit one.
85
+
86
+ ## Promotability
87
+
88
+ We have defined when it is desirable to promote expressions but have not yet
89
+ defined which expressions can actually be promoted. We refer to such
90
+ expressions as "promotable".
91
+
92
+ ### Named locals
93
+
94
+ Promotable expressions cannot refer to named locals. This is not a technical
95
+ limitation with the CTFE engine. While writing ` let x = {expr} ` outside of a
96
+ const context, the user likely expects that ` x ` will live on the stack and be
97
+ initialized at run-time. Although this is not (to my knowledge) guaranteed by
98
+ the language, we do not wish to violate the user's expectations here.
99
+
100
+ ### Single assignment
101
+
102
+ We only promote temporaries that are assigned to exactly once. For example, the
103
+ lifetime of the temporary whose reference is assigned to ` x ` below will not be
104
+ extended.
105
+
106
+ ``` rust
107
+ let x : & 'static i32 = & if cfg! (windows ) { 0 } else { 1 };
108
+ ```
109
+
110
+ Once again, this is not a fundamental limitation in the CTFE engine; we are
111
+ perfectly capable of evaluating such expressions at compile time. However,
112
+ determining the promotability of complex expressions would require more
113
+ resources for little benefit.
114
+
115
+ ### Access to a ` const ` or ` static `
116
+
117
+ Accesses to ` const ` s are always promotable, regardless of the body of the
118
+ ` const ` . For instance, while the previous example was not legal, the
119
+ following would be:
120
+
121
+ ``` rust
122
+ const NOT_WINDOWS : i32 = if cfg! (windows ) { 0 } else { 1 };
123
+ let x : & 'static i32 = & NOT_WINDOWS ;
124
+ ```
125
+
126
+ However, an access to a ` static ` is only promotable within the initializer of
127
+ another ` static ` .
22
128
23
129
### Panics
24
130
0 commit comments