@@ -119,13 +119,12 @@ should not have promoted something, but then it is already too late -- and the
119119dynamic checks for that are exactly the ones we are already doing for constants
120120and statics.
121121
122- ### Panics
122+ ### Panics, overflow and bounds checks
123123
124- Promotion is not allowed to throw away side effects. This includes panicking.
125- Let us look at what happens when we promote ` &(0_usize - 1) ` in a debug build:
126- We have to avoid erroring at compile-time, because that would be promotion
127- breaking compilation, but we must be sure to error correctly at run-time. In
128- the MIR, this looks roughly like
124+ Let us look at what happens when we promote ` &(0_usize - 1) ` in a debug build.
125+ This code is promoted even though we cannot promote code that could fail, and
126+ this code will fail with an overflow error! What is happening? We have to look
127+ at the underlying MIR representation of this code to explain what happens:
129128
130129```
131130_tmp1 = CheckedSub (const 0usize) (const 1usize)
@@ -137,26 +136,27 @@ _res = &_tmp2
137136```
138137
139138Both ` _tmp1 ` and ` _tmp2 ` are promoted. ` _tmp1 ` evaluates to ` (~0, true) ` , so
140- the assertion will always fail at run-time. Computing ` _tmp2 ` fails with a
141- panic, which is thrown away -- so we have no result. In principle, we could
142- generate any code for this because we know the code is unreachable (the
143- assertion is going to fail). Just to be safe, we generate a call to
144- ` llvm.trap ` .
145-
146- As long as CTFE only panics when run-time code would also have panicked, this
147- works out correctly: The MIR already contains provisions for what to do on
148- panics (unwind edges etc.), so when CTFE panics we can generate code that
149- hard-codes a panic to happen at run-time. In other words, * promotion relies on
150- CTFE correctly implementing both normal program behavior and panics* . An
151- earlier version of miri used to panic on arithmetic overflow even in release
152- mode. This breaks promotion, because now promoting code that would work (and
153- could not panic!) at run-time leads to a compile-time CTFE error.
139+ the assertion will always fail at run-time. Computing ` _tmp2 ` evaluates to ` ~0 ` .
140+
141+ In other words, the actually failing check is not promoted, only the computation
142+ that serves as input to the check is promoted.
143+
144+ An earlier version of Miri used to error on arithmetic overflow even in release
145+ mode. This breaks promotion, because now promoting code like ` _tmp1 ` would
146+ introduce promotes that fail to evaluate, which is not acceptable as explained
147+ above!
148+
149+ Something similar but more subtle happens when promoting array accesses: the
150+ bounds check is not promoted, but the array access is. However, before accepting
151+ a temporary for promotion, we ensure that array accesses are definitely
152+ in-bounds. This leads to MIR without bounds checks, but we know the array access
153+ will always succeed.
154154
155155### Const safety
156156
157- We have explained what happens when evaluating a promoted panics, but what about
158- other kinds of failure -- what about hitting an unsupported operation or
159- undefined behavior? To make sure this does not happen, only const safe code
157+ We have explained how we ensure that evaluating a promoted does not panic, but
158+ what about other kinds of failure -- what about hitting an unsupported operation
159+ or undefined behavior? To make sure this does not happen, only const safe code
160160gets promoted. The exact details for ` const safety ` are discussed in
161161[ here] ( const_safety.md ) .
162162
0 commit comments