-
Notifications
You must be signed in to change notification settings - Fork 13k
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
properly short circuit const eval of && and || #29879
Conversation
As described in rust-lang#29608, the rhs of a logical expression is evaluated even if evaluation of the lhs means no such evaluation should take place.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
that's very verbose. I first had the same Idea, but chose to move in a different direction: oli-obk@e427500 I was waiting on #29797 before doing this. Does the following test work for you? const N: usize = 0;
const ARR: [i32; N] = [42; N];
const X: bool = (N > 0) && (ARR[0] == 99);
fn main() {
let _ = X;
} and the following one? const N: usize = 2;
const ARR: [i32; N] = [42; N];
const X: bool = (ARR[0] == 99) && (N == 2);
fn main() {
let _ = X;
} |
@@ -0,0 +1,17 @@ | |||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2015
The first one doesn't work indeed, the second does. Thanks for catching it. Happy to defer to your plans if you like them more :) |
I do find my For the The second one works, because it's not short circuiting, since the first expression returns an const N: usize = 2;
const ARR: [i32; N] = [42; N];
const X: bool = (ARR[0] == 99) && (ARR[99] == 1337);
fn main() {
let _ = X;
} |
Seems related to #29797 |
@@ -591,6 +591,21 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, | |||
let is_float = ty.is_fp(); | |||
let signed = ty.is_signed(); | |||
|
|||
if ty.is_bool() && (b.node == hir::BiOr || b.node == hir::BiAnd) { | |||
match eval_const_expr_partial(cx.tcx(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this doesn't seem sufficient. The trans constant evaluator generally handles a wider set of conditions that eval_const_expr_partial
, so it seems to me that this will result in short-circuiting sometimes working and sometimes (for more complex constants) not working, which doesn't seem like the ideal situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I guess this would still be an improvement towards the eventual goal.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes you're right, see also @oli-obk 's comment. I would need to fix this better somehow, but don't yet know a good way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really hard to extract the proper value from a llvm constant value. There's stackoverflow posts on it for doing it with c++
http://stackoverflow.com/questions/5315176/llvm-get-constant-integer-back-from-value
http://stackoverflow.com/questions/17255699/outputting-inputs-constant-char-array-from-llvm-pass
http://stackoverflow.com/questions/30314417/llvm-retrieving-the-value-of-constant-function-parameters-from-the-c-api
@oli-obk in your code, can't you adjust it pretty easily to avoid evaluating the RHS? e.g. let a = try!(eval_const_expr_partial(tcx, &**a, ty_hint, fn_args));
match (a, b, op.node) {
// short circuit bool ops
(Bool(false), _, BiAnd) => return Bool(false),
(Bool(true), _, BiOr) => return Bool(true),
_ => { }
}
// FIXME: lazy eval b?
let b = eval_const_expr_partial(tcx, &**b, b_ty, fn_args);
match (a, b, op.node) {
(Bool(true), Ok(Bool(rhs)), BiAnd) => Bool(rhs),
(Bool(false), Ok(Bool(rhs)), BiOr) => Bool(rhs),
... // as before
} or am I missing something? |
☔ The latest upstream changes (presumably #29797) made this pull request unmergeable. Please resolve the merge conflicts. |
@nikomatsakis yea, that looks about right. I don't remember if anything spoke against that. I'll modify my code. |
I am torn about this. Do you think guys think it makes sense to move forward with a partial fix here? Or wait until we refactor the trans-based impl away? I'm not a big fan of trying really hard to make the trans-based code work, though maybe that IS more prudent. (Since I don't know whether anyone has time or bandwidth to spearhead an effort to reshape the constant evaluator, though @oli-obk given all your work in this area lately maybe we should try to touch base on that. I'd be eternally grateful. :)) |
I'm perfectly fine with not improving WRT moving to one unified const evaluator, I can't give any promises, but it's likely I'll be posting a new PR whenever I get one merged, so at least there'll be movement forward. |
I could live with that too, though we ought to make some notes on the relevant GH issues.
This is tantalizing but I'm not sure what it means. :) Does this mean you have something in the works? Or you have a long queue of improvements on the way? |
I have plans. And a few horribly outdated commits to rebase. I can create a tracking issue if you want. |
Yes, that's OK with me of course. I agree that implementing partially correct behaviour might be more confusing than leaving it as is for now. Thanks for the review! |
As described in #29608, the rhs of a logical expression is evaluated
even if evaluation of the lhs means no such evaluation should take
place if that evaluation happens in a const context.