@@ -6,11 +6,14 @@ arithmetic.
6
6
7
7
## Rules
8
8
9
- ### 1. No side effects
9
+ ### 1. Panics
10
10
11
11
Promotion is not allowed to throw away side effects. This includes
12
- panicking. let us look at what happens when we promote ` &(0_usize - 1) ` :
13
- In the MIR, this looks roughly like
12
+ panicking. Let us look at what happens when we promote ` &(0_usize - 1) ` in a
13
+ debug build: We have to avoid erroring at compile-time (because that would be
14
+ promotion breaking compilation), but we must be sure to error correctly at
15
+ run-time. In the MIR, this looks roughly like
16
+
14
17
```
15
18
_tmp1 = CheckedSub (const 0usize) (const 1usize)
16
19
assert(!_tmp1.1) -> [success: bb2; unwind: ..]
19
22
_tmp2 = tmp1.0
20
23
_res = &_tmp2
21
24
```
25
+
22
26
Both ` _tmp1 ` and ` _tmp2 ` are promoted to statics. ` _tmp1 ` evaluates to `(~ 0,
23
27
true)` , so the assertion will always fail at run-time. Computing ` _ tmp2` fails
24
28
with a panic, which is thrown away -- so we have no result. In principle, we
25
29
could generate any code for this because we know the code is unreachable (the
26
30
assertion is going to fail). Just to be safe, we generate a call to
27
31
` llvm.trap ` .
28
32
33
+ As long as CTFE only panics when run-time code would also have panicked, this
34
+ works out correctly: The MIR already contains provisions for what to do on
35
+ panics (unwind edges etc.), so when CTFE panics we can generate code that
36
+ hard-codes a panic to happen at run-time. In other words, * promotion relies on
37
+ CTFE correctly implementing both normal program behavior and panics* . An
38
+ earlier version of miri used to panic on arithmetic overflow even in release
39
+ mode. This breaks promotion, because now promoting code that would work (and
40
+ could not panic!) at run-time leads to a compile-time CTFE error.
41
+
29
42
### 2. Const safety
30
43
31
- Only const safe code gets promoted. The exact details for ` const safety ` are
32
- discussed in [ here] ( const_safety.md ) .
44
+ We have explained what happens when evaluating a promoted panics, but what about
45
+ other kinds of failure -- what about hitting an unsupported operation or
46
+ undefined behavior? To make sure this does not happen, only const safe code
47
+ gets promoted. The exact details for ` const safety ` are discussed in
48
+ [ here] ( const_safety.md ) .
33
49
34
50
An example of this would be ` &(&1 as *const i32 as usize % 16 == 0) ` . The actual
35
51
location is not known at compile-time, so we cannot promote this. Generally, we
36
52
can guarantee const-safety by not promoting when an unsafe or unconst operation
37
- is performed. However, things get more tricky when ` const ` and ` const fn ` are
38
- involved.
53
+ is performed -- if our const safety checker is correct, that has to cover
54
+ everything, so the only possible remaining failure are panics.
55
+
56
+ However, things get more tricky when ` const ` and ` const fn ` are involved.
39
57
40
58
For ` const ` , based on the const safety check described [ here] ( const_safety.md ) ,
41
59
we can rely on there not being const-unsafe values in the ` const ` , so we should
42
- be able to promote freely.
43
-
44
- For ` const fn ` , there is no way to check anything in advance. We can either
45
- just not promote, or we can move responsibility to the ` const fn ` and promote
46
- * if* all function arguments pass the const safety check. So, ` foo(42usize) `
47
- would get promoted, but ` foo(&1 as *const i32 as usize) ` would not. When this
48
- call panics, compilation proceeds and we just hard-code a panic to happen as
49
- well at run-time. However, when const evaluation fails with another error, we
50
- have no choice but to abort compilation of a program that would have compiled
51
- fine if we would not have decided to promote. It is the responsibility of ` foo `
52
- to not fail this way when working with const-safe arguments.
60
+ be able to promote freely. For example:
61
+
62
+ ``` rust
63
+ union Foo { x : & 'static i32 , y : usize }
64
+ const A : usize = unsafe { Foo { x : & 1 }. y };
65
+ const B : usize = unsafe { Foo { x : & 2 }. y };
66
+ let x : & bool = & (A < B );
67
+ ```
68
+
69
+ Promoting ` x ` would lead to a compile failure because we cannot compare pointer
70
+ addresses. However, we do not even get there -- computing ` A ` or ` B ` fails with
71
+ a const safety check error because these are values of type ` usize ` that contain
72
+ a ` Scalar::Ptr ` .
73
+
74
+ For ` const fn ` , however, there is no way to check anything in advance. We can
75
+ either just not promote, or we can move responsibility to the ` const fn ` and
76
+ promote * if* all function arguments pass the const safety check. So,
77
+ ` foo(42usize) ` would get promoted, but ` foo(&1 as *const i32 as usize) ` would
78
+ not. When this call panics, compilation proceeds and we just hard-code a panic
79
+ to happen as well at run-time. However, when const evaluation fails with
80
+ another error (unsupported operation or undefined behavior), we have no choice
81
+ but to abort compilation of a program that would have compiled fine if we would
82
+ not have decided to promote. It is the responsibility of ` foo ` to not fail this
83
+ way when working with const-safe arguments.
84
+
85
+ ### 3. Drop
86
+
87
+ TODO: Fill this with information.
88
+
89
+ ### 4. Interior Mutability
90
+
91
+ TODO: Fill this with information.
92
+
93
+ ## Open questions
94
+
95
+ * There is a fourth kind of CTFE failure -- and endless loop being detected.
96
+ What do we do when that happens while evaluating a promoted?
0 commit comments