11# Const promotion
22
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 ` :
414Instead of putting it on the stack, the ` 3 ` is allocated in global static memory
515and a reference with lifetime ` 'static ` is provided. This is essentially an
616automatic transformation turning ` &EXPR ` into
@@ -10,15 +20,111 @@ Note that promotion happens on the MIR, not on surface-level syntax. This is
1020relevant when discussing e.g. handling of panics caused by overflowing
1121arithmetic.
1222
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+
1347On 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* .
1448Thus, if CTFE fails but the code would have worked fine at run-time, we broke the user's code for no good reason.
1549Even 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 ] .
1650That's why we have to be very conservative with what can and cannot be promoted.
1751
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+
1971[ warn-rfc ] : https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
2072
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 ` .
22128
23129### Panics
24130
0 commit comments