@@ -119,13 +119,12 @@ should not have promoted something, but then it is already too late -- and the
119
119
dynamic checks for that are exactly the ones we are already doing for constants
120
120
and statics.
121
121
122
- ### Panics
122
+ ### Panics, overflow and bounds checks
123
123
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:
129
128
130
129
```
131
130
_tmp1 = CheckedSub (const 0usize) (const 1usize)
@@ -137,26 +136,27 @@ _res = &_tmp2
137
136
```
138
137
139
138
Both ` _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.
154
154
155
155
### Const safety
156
156
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
160
160
gets promoted. The exact details for ` const safety ` are discussed in
161
161
[ here] ( const_safety.md ) .
162
162
0 commit comments