-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
const fn's should allow (and eval) assert! and debug_assert! statements #1383
Comments
This is pretty hard, since if !(4 < 5) {
::std::rt::begin_unwind("assertion failed: 4 < 5",
{
static _FILE_LINE: (&'static str, u32)
=
("bla.rs", 2u32);
&_FILE_LINE
})
};
|
@oli-obk yes I was assuming we would have to special-case the two macros (or revise their expansions to call a new special cased macro) |
@oli-obk Error messages from gcc and clang look pretty nice for this case. Our
|
The problem with that approach is that So if we want to make this correct, we need to specify ranges and similar for all arguments, and then check the const fn on its own. A simplified version with pre-conditions: #[pre(b != 0 && (a != i32::MIN || b != -1))]
const fn div(a: i32, b: i32) -> i32 {
a / b
} During the Of course it's incredibly hard to check whether a function will never fail for arbitrary preconditions. I'm sure we can come up with a practical system. |
I don't think this is a reasonable goal. I would be satisfied with errors in these cases being delayed until there is actually a call-site acting as a witness to the erroneous condition. (In which case one would just express pre-conditions via |
@oli-obk |
I was under the impression that const functions should be checked if they contain errors even if they are not called. I can't find the comment I'm referring to and I'm not sure how far it was meant. It might just be for errors that occur unconditionally with any input.
It was a goal for generics. But generic functions are used everywhere. The question is whether we want to take a different path than other languages or if all those specifications would be too much hazzle considering that const fn might be used rarely even once stabilized. |
Such preconditions may be closely related to bounds on integer type paremeters (if they are ever considered to be a way to go). |
Yes, I agree with that. There is reasonably well-established foundation (update: and precedent) for using the type-system as a theorem-prover for statically checking generics, and so we make use of that. I don't think we want to impose the same set of restrictions on (But then again, who knows what will come in the future with respect to Rust's attitude towards dependently-typed programming... maybe my mental model is stuck in the dark ages...) |
Yes, my intention was to catch every const eval failure. So, how about an attribute for non-const functions that makes them usable in const functions until they are evaluated? The attribute could take a string or an ident as the argument. In case of an ident, the content of the function's argument with that name will be printed as the error. Then we can mark |
We could also just make |
@Kimundi well, your use of the word "just" may be a little misleading, since there are other changes that would need to be made to (namely, we'd need to loosen the current restriction that "blocks in constant functions are limited to items and tail expressions [E0016]") |
Oh, I didn't mean to imply it would be easy, just that as far as language changes are concerned adding another lang item seemed simpler than some of the other proposals here. :) |
I am with @Kimundi on this one - this came up a while ago, and I even suggested interpreting format arguments at compile-time, although that is overkill here. If we rely on rvalue promotion, we can do the following: if !(4 < 5) {
::std::rt::begin_unwind("assertion failed: 4 < 5", &("bla.rs", 2u32));
} That requires implementing |
I implemented this, but there's a small issue... panics end up expanding to if !(4 < 5) {
static _FILE_LINE: (&'static str, u32) = ("bla.rs", 2u32);
::std::rt::begin_unwind("assertion failed: 4 < 5", &_FILE_LINE);
} Putting statics into const fns is allowed, but referencing them is not. Playpen |
It's not an implementation issue, constants are not allowed to access statics in Rust. To lift that restriction we need an rfc, right? I don't even know if it makes sense to lift the restriction. |
@oli-obk There isn't even an access there, it's just taking a reference. Completely harmless in my model, which miri is roughly following. Even reading a |
The last thing I got told about constants referencing statics: rust-lang/rust#25570 (comment) ;) |
@oli-obk The context is that in the current system, only trans could complain about |
@eddyb The blocker is
See line 795 which is the |
@tsion Would it be possible to have |
@eddyb Yes, that seems doable. By the way, I think the reason I left |
Closing in favor of rust-lang/rust#51999. |
Right now we have ad hoc checks for certain known bad scenarios in our const evaluator ... so for example:
the above code today evaluates like so (playpen) in debug mode:
and in release mode:
(i.e., there is no way to emulate the
foo
behavior withinbar
while compiling in release mode.)Another example: since we made the
NonZero
constructor a const function, we cannot add adebug_assert!
to its body that checks that the input is actually non-zero. (If it were not a const function, then it is straight-forward to extend theZeroable
trait with anfn is_zero(&self) -> bool
predicate to use as the basis for such a `debug_assert!).I don't feel like writing up a formal RFC yet for addressing this, but I think it would be nice to extend the
const fn
sublanguage to allowassert!
anddebug_assert!
statements where the input text expression is restricted to a const expression, and then haverustc
actually fail the compilation if it discovers an assertion violation at compile-time.The text was updated successfully, but these errors were encountered: