On Mon, Sep 8, 2025 at 3:54 PM Iain Sandoe <[email protected]> wrote: > > > > > On 8 Sep 2025, at 14:40, Richard Biener <[email protected]> wrote: > > > > On Mon, Sep 8, 2025 at 3:16 PM Jakub Jelinek <[email protected]> wrote: > >> > >> On Mon, Sep 08, 2025 at 03:05:58PM +0200, Richard Biener wrote: > >>> is reduced to __builtin_abort () (for C++). That's because it's > >>> __builtin_unreachable () at the end. I am not aware of any > >>> other "UB" than missed return that we turn into unreachable(), > >>> even > >>> > >>> unsigned int foo (unsigned int i) > >>> { > >>> if (i < 33) > >>> __builtin_abort (); > >>> return i << i; > >>> } > >>> > >>> isn't handled this way. But sure we could, in the future. > >>> std::... before the return would help in case it is considered > >>> a barrier that might not continue to the UB. > >> > >> What is gimple-ssa-isolate-paths.cc doing then? > > > > Nothing in the above case - we only isolate null pointer dereferences > > IIRC. > > > >> I thought it is about obvious UBs like null pointer dereferences etc. > >> and the whole paths can be turned into e.g. __builtin_trap() with it > >> and for anything dominated by the UB that is just fine from the POV of this > >> C++ paper and it only a question if we don't propagate it also backwards > >> across calls (or other statements if std::observable_checkpoint would be > >> e.g. inline function with nothing in it and no special attributes). > > > > So I've now read the paper and it's motivated by C++ contracts. > > I think that is considered to be a first use - but not (AFAIU the only > potential > use) > > > I have > > no idea how they'd be actually implemented, so I can't say if it's sensible > > for those. > > (for pre-conditions) they lower to a series of statements like > if (some check fails) > handle the contract violation > if (some other check fails) > handle the contract violation > … > > > The only "example" is for in(p) in (*p > 5) where the contract > > *p > 5 would "elide" the 'p' one. Whatever "eliding" means here. > > So, IIRC, the argument was > > *p > 5 would be UB for p == nullptr > > therefore an earlier check for p == nulptr can be removed, because > that case cannot happen in a well-formed program. > > However, that prevents the contract check from doing its job (diagnosing > the bad case).
But only if "handle the contract violation" continues to check *p > 5 anyway, which would then segfault? I'm confused as to how that's useful. I guess it might be better to have "dependent" contracts, in(p, in(*p > 5)) in (q) implemented as if (!p) handle violation else if (!(*p > 5)) handle violation if (!q) // independent handle violation This would have no such issue (and also not segfault during contract evaluation). > I cannot say that GCC would make that optimisation - it was, in general, > quite hard to find cases that time-traveled. I think such optimization would be valid. Richard. > Iain > > > > > Richard. > > > >> Jakub >
