Skip to content

Commit 9ed92f8

Browse files
committed
Allow panicking in constants
1 parent 1706316 commit 9ed92f8

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

text/0000-const-panic.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
- Feature Name: const_panic
2+
- Start Date: 2018-02-22
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Allow the use of `panic!`, `assert!` and `assert_eq!` within constants and
10+
report their evaluation as a compile-time error.
11+
12+
# Motivation
13+
[motivation]: #motivation
14+
15+
It can often be desirable to terminate a constant evaluation due to invalid
16+
arguments. Currently there's no way to do this other than to use `Result` to
17+
produce an `Err` in case of errors. Unfortunately this will end up as a runtime
18+
problem and not abort compilation, even though the problem has been detected at
19+
compile-time. There are already ways to abort compilation, e.g. by invoking
20+
`["some assert failed"][42]` within a constant, which will abort with a
21+
compile-time error pointing at the span of the index operation. But this hack is
22+
not very convenient to use and produces the wrong error message.
23+
24+
# Guide-level explanation
25+
[guide-level-explanation]: #guide-level-explanation
26+
27+
You can now use `panic!` and `assert!` within `const fn`s. This means that when
28+
the const fn is invoked at runtime, you will get a regular panic, but if it is
29+
invoked at compile-time, the panic message will show up as an error message.
30+
31+
As an example, imagine a function that converts strings to their corresponding
32+
booleans.
33+
34+
```rust
35+
const fn parse_bool(s: &str) -> bool {
36+
match s {
37+
"true" => true,
38+
"false" => false,
39+
other => panic!("`{}` is not a valid bool"),
40+
}
41+
}
42+
parse_bool("true");
43+
parse_bool("false");
44+
parse_bool("foo");
45+
```
46+
47+
will produce an error with your custom error message:
48+
49+
```
50+
error[E0080]: `foo` is not a valid bool
51+
--> src/main.rs: 5:25
52+
|
53+
5 | other => panic!("`{}` is not a valid bool"),
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
note: during the evaluation of
56+
|
57+
10 | parse_bool("foo");
58+
| ^^^^^^^^^^^^^^^^^
59+
```
60+
61+
# Reference-level explanation
62+
[reference-level-explanation]: #reference-level-explanation
63+
64+
MIR interpretation gets a special case for the panic machinery (which isn't
65+
const fn). If the `panic` lang item is entered, instead of producing an error
66+
about it not being const fn, we produce a specialized error with the panic's
67+
message. This panic reporting machinery is already present in the mir
68+
interpreter, but needs the lang item detection in order to work.
69+
70+
# Drawbacks
71+
[drawbacks]: #drawbacks
72+
73+
We have to implement some magic around processing `fmt::Arguments` objects and
74+
producing the panic message from that.
75+
76+
# Rationale and alternatives
77+
[alternatives]: #alternatives
78+
79+
* We could add a special constant error reporting mechanism. This has the
80+
disadvantage of widening the gap between const eval and runtime execution.
81+
* We could make `String` and formatting const enough to allow the panic
82+
formatting machinery to be interpreted and made const fn
83+
* Don't produce a good error message, just say "const eval encountered an error"
84+
and point the user to the panic location. This already works out of the box
85+
right now. We can improve the error message in the future with the `String` +
86+
formatting alternative. This is the most minimalistic alternative to this RFC
87+
88+
# Unresolved questions
89+
[unresolved]: #unresolved-questions
90+
91+
* Should there be some additional message in the error about this being a panic
92+
turned error? Or do we just produce the exact message the panic would produce?
93+
94+
* This change becomes really useful if `Result::unwrap` and `Option::unwrap`
95+
become const fn, doing both in one go might be a good idea

0 commit comments

Comments
 (0)