> 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
>> 

Reply via email to