Is it time to take the middle-end stringop/array warnings out of -Wall?
Martin Uecker
muecker@gwdg.de
Fri May 22 14:54:46 GMT 2026
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 <MatthiasKretz@gmx.net>:
> >
> > > 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
More information about the Gcc
mailing list