> On 8 Sep 2025, at 15:01, Richard Biener <richard.guent...@gmail.com> wrote:
>
> On Mon, Sep 8, 2025 at 3:54 PM Iain Sandoe <i...@sandoe.co.uk> wrote:
>>
>>
>>
>>> On 8 Sep 2025, at 14:40, Richard Biener <richard.guent...@gmail.com> wrote:
>>>
>>> On Mon, Sep 8, 2025 at 3:16 PM Jakub Jelinek <ja...@redhat.com> 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).
sure, and just writing
pre ( p && *p > 5)
will also DTRT without changng the current syntax (too
late to do that now, for c++26, I;d think)
I believe the intent is to try and improve things in the general
case - perhaps, with more complex expressions, the logic would
be less obvious.
>> 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.
ack .. thaks.
Iain
>
> Richard.
>
>> Iain
>>
>>>
>>> Richard.
>>>
>>>> Jakub
>>