Comment by Windeycastle
4 days ago
The way I reason about it is that the contracts are more soft conditions that you expect to not really reach. If something always has to be true, even on not-safe mode, you use "actual" code inside the function/macro to check that condition and fail in the desired way.
>The way I reason about it is that the contracts are more soft conditions that you expect to not really reach
What's the difference from an assert then?
The difference from an assert is that for "require" they are compiled into the caller frame, so things like stack traces (which is available in safe mode) will point exactly to where the violation happened.
Because of inlining them at the call site happens, static analysis will already pick up some obvious violations.
Finally, these contracts may be used to compile time check otherwise untyped arguments to macros.
“However, violating either pre- or post-conditions is unspecified behaviour, and a compiler may optimize code as if they are always true – even if a potential bug may cause them to be violated”
This implies that a compiler would be permitted to remove precisely that actual code that checks the condition in non-safe mode.
Seems like a deliberately introduced footgun.
My understanding of this was that the UB starts only after the value is passed/returned. So if foo() has a contract to only return positive integers, the code within foo can check and ensure this, but if the calling code does it, the compiler might optimize it away.
Assuming that is correct, it's still exactly the same footgun. Checks like that are introduced to guard against bugs: you are strictly safer to not declare such a constraint.
Unspecified behavior != UB https://en.wikipedia.org/wiki/Unspecified_behavior