3 ms·
> using "a pointer was dereferenced" as evidence "this pointer is safe to dereference" is comically bad evidence Do you think the compiler would be right to re
by gpderetta 4y ago
> using "a pointer was dereferenced" as evidence "this pointer is safe to dereference" is comically bad evidence
Do you think the compiler would be right to remove the second check here?
if (!x) std::abort();
if (!x) return;
... = *x;
What about changing std::abort with the following?
[[noreturn]] void my_abort();
How's that different form a check after dereferencing a pointer? In both cases the check can be removed because dataflow or control flow analysis.
What if my_abort returns instead? Or another thread changes x after the fact?
- vintermann 4y agoIf I had written the above code, I had clearly done something wrong. I would not want the compiler to remove the second check. I'd want it to (at the very least) warn me about an unreachable return statement, so that I could remove the actual meaningless code. It's been long enough since I wrote C that I'm not familiar with that noreturn syntax or the contract I guess it implies, but control flow analysis which can prove the code will never be run, should all ideally warn me about it so that I can remove it in the source code, not quietly remove it from the object code. I'm not demanding that it should happen in every case, but the cases where it's undecidable whether a statement is reachable or not, obviously it's undecidable for purposes of optimizing away the statement too.
- gpderetta 4y agoThe first check might be in a completely different function in another module (for example a postcondition check before a return). Removing dead code is completely normal and desirable, warning every time it happens would be completely pointless and wrong.
- xigoi 4y agoif (!x) std::abort(); if (!x) return; In this case, the compiler should warn that the second statement will never be executed, instead of just silently removing it.
- gpderetta 4y agoint *x = libX_foo(); if (!x) { return; } ... libX_foo from libX gets at some point updated to abort if the return value would be null. After interprocedural analysis (possibly during LTO) the compiler infers that the if statement is redundant. Should the compiler complain? Should you remove the check? Consider that libX_foo returning not-null might not be part of the contract and just an implementation detail of this version.
- xigoi 4y ago> Should the compiler complain? Should you remove the check? Yes and yes. > Consider that libX_foo returning not-null might not be part of the contract and just an implementation detail of this version. How is it an “implementation detail” whether a procedure can return null? That's always an important part of its interface.
- gpderetta 4y agoThe contract is that libX_foo can return null. But a specific implementation might not. Now you need to remove the caller side check to shut up the compiler which will leave you exposed to a future update making full use of the contract. Also consider code that call libX_foo via a pointer. After specialization the compiler might see that the check is redundant, but you can't remove the check because the function might still be called with other function pointers making full use of the contract.
- xigoi 4y ago> The contract is that libX_foo can return null. I'd expect any reasonable library to say “libX_foo returns null if [something happens]”. What use is there in a procedure that can just return null whenever it feels like it?
- account42 4y agoIt returns null when it fails to do its task for some reason. It is not unreasonable for the condition for that failure to be complex enough or change over time so it doesn't make sense to spell it out in the interface contract.