Am Freitag, dem 22.05.2026 um 15:24 +0200 schrieb Matthias Kretz via Gcc:
> Richard Biener via Gcc [Friday, 22 May 2026, 14:52:05 CEST]:
> > 
> > 
> > > Am 22.05.2026 um 13:49 schrieb Matthias Kretz <[email protected]>:
> > 
> > > Jason Merrill via Gcc [Thursday, 21 May 2026, 20:12:01 CEST]:
> > 
> > 
> > 
> > > > This seems too broad a category;
> > 
> > 
> > 
> > > I think it's a very interesting category. But, with that name, it's not
> > > very discoverable for users.
> > > 
> > > My experience with these kinds of warnings (and I implemented library
> > > precondition checking in a similar manner) is that they can be resolved by
> > > precondition checking that is visible to the optimizer. I like to think of
> > > this as "forcing precondition checks to bubble up".
> > > 
> > > Consider:
> > >  char str[] = "Hello";
> > >  
> > >  // precondition: cond == false
> > >  char
> > >  f(bool cond)
> > >  { return cond ? str[100] : str[0]; }
> > > 
> > > This warns about str[100] being out of bounds. But the real problem was
> > > that f was called out-of-contract. If we add "pre (cond == false)" and
> > > compile with -fno-contracts-conservative-ipa (and a terminating contracts
> > > evaluation semantic) the warning goes away.
> > > 
> > > So you can think about these warnings as "your function is missing a
> > > precondition check". Conceptually. Because C++ contracts currently default
> > > to hiding from the optimizer.
> > > 
> > > Thus:
> > > 1. middle-end warnings should hint at missing precondition checks
> > > 2. middle-end warnings maybe should only be on by default if contracts
> > > checking is visibly (to the optimizer) terminating. (I've been using
> > > __builtin_trap for this.)
> > > 
> > > On the name: "-Wmiddle-end" is an explanation to compiler devs and nobody
> > > else. How about something in the direction of "-Wstatic-precondition-
> > > checking"?
> > 
> > I think this is a good observation.  Much like that diagnostics that do this
> > should probably enable diagnostic-paths, at least for their emitted
> > diagnostics.  Because the path is what shows the currently visible
> > preconditions.  Remember that esp. with C++ the set of visible
> > preconditions is heavily dependent on inlining decisions.
> 
> Right. The other "solution" to remove the warning for f(bool) above is to 
> declare it inline. Then it's up to the caller to get precondition checks 
> right. Like this (https://compiler-explorer.com/z/E5GKfaWYz):
> 
> char str[10] = {};
> 
> // precondition: !cond
> inline char
> f(bool cond)
> { return cond ? str[100] : str[0]; }
> 
> // precondition: x < 0
> char
> g(int x)
> {
>   if (x >= 0) __builtin_trap(); // remove => the warning is emitted
>   return f(x > 0);
> }
> 
>  --- * ---
> 
> For reference, this is the precondition check macro I use while developing 
> std::simd:
> 
> #define _GLIBCXX_SIMD_LOC __FILE__ ":" _GLIBCXX_SIMD_TOSTRING(__LINE__) ": "
> 
> #define __glibcxx_simd_precondition(expr, msg, ...)                          \
>   do {                                                                       \
>     const bool __precondition_result = !bool(expr);                          \
>     if (__builtin_constant_p(__precondition_result) && __precondition_result)\
>       {                                                                      \
>         struct _Precondition                                                 \
>         {                                                                    \
>           [[__gnu__::__noipa__, __gnu__::__warning__("precondition failure. "\
>             "\n" _GLIBCXX_SIMD_LOC "note: " msg " (precondition '" #expr     \
>             "' does not hold)")]]                                            \
>           static inline void _S_fail() noexcept {}                           \
>         };                                                                   \
>         _Precondition::_S_fail();                                            \
>       }                                                                      \
>     if (__builtin_expect(__precondition_result, false))                      \
>       std::simd::__invoke_ub(                                                \
>         _GLIBCXX_SIMD_LOC "precondition failure in '%s':\n" msg " ('" #expr  \
>         "' does not hold)", __PRETTY_FUNCTION__ __VA_OPT__(,) __VA_ARGS__);  \
>   } while(false)
> 
> 
> I recently wrote (B is an mdspan):
> 
>   simd::unchecked_load<V>(&B[k, 0], &B[k, M-1], simd::flag_aligned);
> 
> where I wanted to load a matrix row of M values. The end iterator is off-by-
> one. And this is what I got:
> 
> /home/mkretz/src/simd/include/bits/simd_details.h|87 col 31 warning| call to 
> 'std::simd::unchecked_load<basic_vec<float, _Abi<8, 1, 0> >, std::span<const 
> float, 18446744073709551615>, __aligned_flag>(std::span<const float, 
> 18446744073709551615>&&, flags<__aligned_flag>)::_Precondition::_S_fail' 
> declared with attribute warning: precondition failure. 
> /home/mkretz/src/simd/include/bits/simd_loadstore.h|65| note: Input range is 
> too small. Did you mean to use 'partial_load'? (precondition 
> 'std::ranges::size(__r) >= _RV::size()' does not hold) [-Wattribute-warning]
> 
> Running the program traps by default. With -D_GLIBCXX_ASSERTIONS, running the 
> program aborts after printing:
> 
> /home/mkretz/src/simd/include/bits/simd_loadstore.h|65| precondition failure 
> in 'constexpr std::simd::__vec_load_return_t<_Vp, 
> std::ranges::range_value_t<_View> > std::simd::unchecked_load(_Rg&&, 
> flags<_Flags ...>) [with _Vp = basic_vec<float, _Abi<8, 1, 0> >; _Rg = 
> std::span<const float, 18446744073709551615>; _Flags = {__aligned_flag}; 
> __vec_load_return_t<_Vp, std::ranges::range_value_t<_View> > = 
> basic_vec<float, _Abi<8, 1, 0> >; std::ranges::range_value_t<_View> = float]':
> Input range is too small. Did you mean to use 'partial_load'? 
> ('std::ranges::size(__r) >= _RV::size()' does not hold)
> 
> 
> Somewhat similar to -fhardened, I think this is a useful build-mode to have.
> 
> - Matthias

Indeed, and for similar reasons, I wanted to have a warning option for
__builtin_trap() when not ellided, because this allows me to get
compile-time warning for UBsan inserted checks that are not eliminated
by the compiler.  I find this extremeley useful, and I do not even
have to insert the checks myself. 

Example: https://godbolt.org/z/qdWMrx6do


Martin




Martin






Reply via email to