|
| 1 | +- Feature Name: compile_time_asserts |
| 2 | +- Start Date: 2015-07-30 |
| 3 | +- RFC PR: (leave this empty) |
| 4 | +- Rust Issue: (leave this empty) |
| 5 | + |
| 6 | +# Summary |
| 7 | + |
| 8 | +If the constant evaluator encounters erronous code during the evaluation of |
| 9 | +an expression that is not part of a true constant evaluation context a warning |
| 10 | +must be emitted and the expression needs to be translated normally. |
| 11 | + |
| 12 | +# Definition of constant evaluation context |
| 13 | + |
| 14 | +There are exactly five places where an expression needs to be constant. |
| 15 | + |
| 16 | +- the initializer of a constant `const foo: ty = EXPR` or `static foo: ty = EXPR` |
| 17 | +- the size of an array `[T; EXPR]` |
| 18 | +- the length of a repeat expression `[VAL; LEN_EXPR]` |
| 19 | +- C-Like enum variant discriminant values |
| 20 | +- patterns |
| 21 | + |
| 22 | +In the future the body of `const fn` might also be interpreted as a constant |
| 23 | +evaluation context. |
| 24 | + |
| 25 | +Any other expression might still be constant evaluated, but it could just |
| 26 | +as well be compiled normally and executed at runtime. |
| 27 | + |
| 28 | +# Motivation |
| 29 | + |
| 30 | +Expressions are const-evaluated even when they are not in a const environment. |
| 31 | + |
| 32 | +For example |
| 33 | + |
| 34 | +```rust |
| 35 | +fn blub<T>(t: T) -> T { t } |
| 36 | +let x = 5 << blub(42); |
| 37 | +``` |
| 38 | + |
| 39 | +will not cause a compiler error currently, while `5 << 42` will. |
| 40 | +If the constant evaluator gets smart enough, it will be able to const evaluate |
| 41 | +the `blub` function. This would be a breaking change, since the code would not |
| 42 | +compile anymore. (this occurred in https://github.com/rust-lang/rust/pull/26848). |
| 43 | + |
| 44 | +# Detailed design |
| 45 | + |
| 46 | +The PRs https://github.com/rust-lang/rust/pull/26848 and https://github.com/rust-lang/rust/pull/25570 will be setting a precedent |
| 47 | +for warning about such situations (WIP, not pushed yet). |
| 48 | + |
| 49 | +When the constant evaluator fails while evaluating a normal expression, |
| 50 | +a warning will be emitted and normal translation needs to be resumed. |
| 51 | + |
| 52 | +# Drawbacks |
| 53 | + |
| 54 | +None, if we don't do anything, the const evaluator cannot get much smarter. |
| 55 | + |
| 56 | +# Alternatives |
| 57 | + |
| 58 | +## allow breaking changes |
| 59 | + |
| 60 | +Let the compiler error on things that will unconditionally panic at runtime. |
| 61 | + |
| 62 | +## insert an unconditional panic instead of generating regular code |
| 63 | + |
| 64 | +GNAT (an Ada compiler) does this already: |
| 65 | + |
| 66 | +```ada |
| 67 | +procedure Hello is |
| 68 | + Var: Integer range 15 .. 20 := 21; |
| 69 | +begin |
| 70 | + null; |
| 71 | +end Hello; |
| 72 | +``` |
| 73 | + |
| 74 | +The anonymous subtype `Integer range 15 .. 20` only accepts values in `[15, 20]`. |
| 75 | +This knowledge is used by GNAT to emit the following warning during compilation: |
| 76 | + |
| 77 | +``` |
| 78 | +warning: value not in range of subtype of "Standard.Integer" defined at line 2 |
| 79 | +warning: "Constraint_Error" will be raised at run time |
| 80 | +``` |
| 81 | + |
| 82 | +I don't have a GNAT with `-emit-llvm` handy, but here's the asm with `-O0`: |
| 83 | + |
| 84 | +```asm |
| 85 | +.cfi_startproc |
| 86 | +pushq %rbp |
| 87 | +.cfi_def_cfa_offset 16 |
| 88 | +.cfi_offset 6, -16 |
| 89 | +movq %rsp, %rbp |
| 90 | +.cfi_def_cfa_register 6 |
| 91 | +movl $2, %esi |
| 92 | +movl $.LC0, %edi |
| 93 | +movl $0, %eax |
| 94 | +call __gnat_rcheck_CE_Range_Check |
| 95 | +``` |
| 96 | + |
| 97 | + |
| 98 | +# Unresolved questions |
| 99 | + |
| 100 | +## Const-eval the body of `const fn` that are never used in a constant environment |
| 101 | + |
| 102 | +Currently a `const fn` that is called in non-const code is treated just like a normal function. |
| 103 | + |
| 104 | +In case there is a statically known erroneous situation in the body of the function, |
| 105 | +the compiler should raise an error, even if the function is never called. |
| 106 | + |
| 107 | +The same applies to unused associated constants. |
0 commit comments