4 ms·
I don't get how changing to if else fixes this. The compiler can still reason that the condition is always going to be true (and if it isn't that is undefined b
by perryizgr8 3y ago
I don't get how changing to if else fixes this. The compiler can still reason that the condition is always going to be true (and if it isn't that is undefined behavior, so f it). And then it will elide the comparison. Same result. The compiler bug here is that for some reason it is not able to apply a valid (lol) optimisation to if else statements. The author should not rely on this. Compiler authors will eventually fix this bug and his game will break again.
- aw1621107 3y ago> I don't get how changing to if else fixes this. The compiler can still reason that the condition is always going to be true No, the compiler can't make that assumption for an if statement. That's because the condition of an if statement is always evaluated first, so the following expression(s) are only conditionally evaluated. There's nothing the compiler can do to reason "backwards" in such a case. then_some effectively flips the order around - the consequent of the "if" statement is evaluated first, and then the condition is evaluated. This reversal of the order makes all the difference. For a more concrete example, consider the following snippets: if (ptr != nullptr) { return *ptr; } else { return nullptr; } This is (probably) safe. The condition is evaluated first, and only if the condition is true is *ptr evaluated. The buggy code, on the other hand, was more like (ptr != nullptr).then_some(*ptr) In this case, the argument *ptr is evaluated first, before the condition. This is sort of equivalent to: result = *ptr if (ptr != nullptr) { return result; } else { return nullptr; } And that is definitely buggy, as it unconditionally dereferences ptr. There isn't really a compiler bug here; it's just language semantics coupled with unsafe.
- gpderetta 3y agoAn alternative way to see this is that it is conditional execution while then_some is a form of predication.
- DannyBee 3y agoThis is all overly complicated. Then_some just has its arguments eagerly evaluated and then (and if/then) do not
- perryizgr8 3y ago> the condition of an if statement is always evaluated first I am not sure about Rust, but gcc will definitely elide an if check if it detects pointer dereference inside the if block. The reasoning was that if a pointer is being dereferenced, it must be non null. Because if it is null that would be undefined behavior and compiler is allowed to do whatever wants in that case anyway. So if (ptr != NULL) { val = *ptr // do something with val } becomes // null check removed val = *ptr // do something with val So no, the condition is not guaranteed to be evaluated first, or even evaluated at all. I would be surprised if Rust compiler is not doing these sorts of optimisations.
- nolist_policy 3y agoSource? I think you remember it wrong: The compiler will only optimize the if away if you already potentially invoked UB. Like this: val = *ptr; // May be *NULL if (*ptr != NULL) ...
- vardump 3y agoThat's not true. Only if you dereferenced the pointer before the if-statement.
- aw1621107 3y ago> but gcc will definitely elide an if check if it detects pointer dereference inside the if block As others have stated, this is almost certainly incorrect. > The reasoning was that if a pointer is being dereferenced, it must be non null. The key here is "if a pointer is being dereferenced". In that case the pointer is only dereferenced if the condition evaluates to true and does nothing otherwise. The optimizer would be incorrect to turn that into an unconditional dereference.