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
>

Reply via email to