On Thu, Dec 7, 2023 at 2:07 PM Jonathan Wakely <jwak...@redhat.com> wrote:
>
> Tested x86_64-linux. Pushed to trunk.
>
> -- >8 --
>
> The changes in r14-6198-g5e8a30d8b8f4d7 were broken, as I used
> _GLIBCXX17_CONSTEXPR for the 'if _GLIBCXX17_CONSTEXPR (true)' condition,
> forgetting that it would also be used for the is_constant_evaluated()
> check. Using 'if constexpr (std::is_constant_evaluated())' is a bug.
>
> Additionally, relying on __glibcxx_assert_fail to give a "not a constant
> expression" error is a problem because at -O0 an undefined reference to
> __glibcxx_assert_fail is present in the compiled code. This means you
> can't use libstdc++ headers without also linking to libstdc++ for the
> symbol definition.
>
> This fix rewrites the __glibcxx_assert macro again. This still avoids
> doing the duplicate checks, once for constexpr and once at runtime (if
> _GLIBCXX_ASSERTIONS is defined). When _GLIBCXX_ASSERTIONS is defined we
> still rely on __glibcxx_assert_fail to give a "not a constant
> expression" error during constant evaluation (because when assertions
> are defined it's not a problem to emit a reference to the symbol). But
> when that macro is not defined, we use a new inline (but not constexpr)
> overload of __glibcxx_assert_fail to cause compilation to fail. That
> inline function doesn't cause an undefined reference to a symbol in the
> library (and will be optimized away anyway).
>
> We can also add always_inline to the __is_constant_evaluated function,
> although this doesn't actually matter for -O0 and it's always inlined
> with any optimization enabled.

I know this is an old patch but I am curious if we should include
__builtin_unreachable() in __glibcxx_assert_fail for the current case
where it is empty?
I was looking into PR 121280 where it uses front/back without checking
if the vector is empy and GCC is producing a warning which is not easy
to understand but seems correct due to this undefinedness (well a
missed jump threading). Do we think the warning should stay or adding
the unreachable in __glibcxx_assert_fail is a good idea?

Note I suspect we don't want to add the unreachable. But maybe it is
better to aways enable the assert instead?

Thanks,
Andrew

>
> libstdc++-v3/ChangeLog:
>
>         PR libstdc++/112882
>         * include/bits/c++config (__is_constant_evaluated): Add
>         always_inline attribute.
>         (_GLIBCXX_DO_ASSERT): Remove macro.
>         (__glibcxx_assert): Define separately for assertions-enabled and
>         constexpr-only cases.
> ---
>  libstdc++-v3/include/bits/c++config | 33 ++++++++++++++++++++---------
>  1 file changed, 23 insertions(+), 10 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index 284d24d933f..25d37428fc1 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -538,6 +538,7 @@ namespace std
>    // This can be used without checking if the compiler supports the feature.
>    // The macro _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED can be used to check if
>    // the compiler support is present to make this function work as expected.
> +  __attribute__((__always_inline__))
>    _GLIBCXX_CONSTEXPR inline bool
>    __is_constant_evaluated() _GLIBCXX_NOEXCEPT
>    {
> @@ -598,19 +599,31 @@ namespace std
>  #endif
>
>  #if defined(_GLIBCXX_ASSERTIONS)
> -# define _GLIBCXX_DO_ASSERT true
> -#elif _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
> -# define _GLIBCXX_DO_ASSERT std::__is_constant_evaluated()
> -#else
> -# define _GLIBCXX_DO_ASSERT false
> -#endif
> -
> +// Enable runtime assertion checks, and also check in constant expressions.
>  # define __glibcxx_assert(cond)                                              
>   \
>    do {                                                                 \
> -    if _GLIBCXX17_CONSTEXPR (_GLIBCXX_DO_ASSERT)                       \
> -      if (__builtin_expect(!bool(cond), false))                              
>   \
> -       _GLIBCXX_ASSERT_FAIL(cond);                                     \
> +    if (__builtin_expect(!bool(cond), false))                          \
> +      _GLIBCXX_ASSERT_FAIL(cond);                                      \
>    } while (false)
> +#elif _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
> +// Only check assertions during constant evaluation.
> +namespace std
> +{
> +  __attribute__((__always_inline__,__visibility__("default")))
> +  inline void
> +  __glibcxx_assert_fail()
> +  { }
> +}
> +# define __glibcxx_assert(cond)                                              
>   \
> +  do {                                                                 \
> +    if (std::__is_constant_evaluated())                                      
>   \
> +      if (__builtin_expect(!bool(cond), false))                              
>   \
> +       std::__glibcxx_assert_fail();                                   \
> +  } while (false)
> +#else
> +// Don't check any assertions.
> +# define __glibcxx_assert(cond)
> +#endif
>
>  // Macro indicating that TSAN is in use.
>  #if __SANITIZE_THREAD__
> --
> 2.43.0
>

Reply via email to