https://gcc.gnu.org/g:c540ece09c8db360a1d6c0e3826a0e942b7e95c7
commit c540ece09c8db360a1d6c0e3826a0e942b7e95c7 Author: Alexandre Oliva <[email protected]> Date: Thu Apr 9 18:55:41 2026 -0300 libstdc++: check value in std::{con,dis}junction When std::{con,dis}junction is passed a type that doesn't have a "value" static data member, or whose value doesn't convert to bool, is ambiguous or inaccessible, we stop iterating over the types and use that type for the {con,dis}junction, without any diagnosis. We'd get a diagnostic when attempting to use its value data member as a bool, but if the member isn't used, compilation is successful, despite the failure to meet the requirements for "value" in [meta.logical]/4. Check that the selected type parameter's value member is convertible to bool. for libstdc++-v3/ChangeLog * include/std/type_traits (disjunction, conjunction): Check that value converts to bool. Diff: --- libstdc++-v3/include/std/type_traits | 15 ++++++++++-- .../logical_traits/requirements/junction_neg.cc | 27 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 59be925e10a6..238450518c08 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -241,10 +241,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // namespace __detail /// @endcond + template<typename _From, typename _To> + struct is_convertible; + template<typename... _Bn> struct conjunction : __detail::__conjunction_impl<void, _Bn...>::type - { }; + { + static_assert(is_convertible<decltype(__detail::__conjunction_impl<void, _Bn...> + ::type::value), bool>::value, + "result type's value is not convertible to bool"); + }; template<> struct conjunction<> @@ -254,7 +261,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename... _Bn> struct disjunction : __detail::__disjunction_impl<void, _Bn...>::type - { }; + { + static_assert(is_convertible<decltype(__detail::__disjunction_impl<void, _Bn...> + ::type::value), bool>::value, + "result type's value is not convertible to bool"); + }; template<> struct disjunction<> diff --git a/libstdc++-v3/testsuite/20_util/logical_traits/requirements/junction_neg.cc b/libstdc++-v3/testsuite/20_util/logical_traits/requirements/junction_neg.cc new file mode 100644 index 000000000000..eb0f246367f1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/logical_traits/requirements/junction_neg.cc @@ -0,0 +1,27 @@ +// { dg-do compile { target c++17 } } + +#include <type_traits> + +class S {}; // not convertible to bool + +struct T { + static constexpr S value{}; +}; + +// 4 Every template type argument for which Bi::value is instantiated shall be +// usable as a base class and shall have a member value which is convertible to +// bool, is not hidden, and is unambiguously available in the type. + +std::conjunction<T> cT; // { dg-error "here" } +std::conjunction<T, std::true_type> cTt; // { dg-error "here" } +std::conjunction<T, std::false_type> cTf; // { dg-error "here" } +std::conjunction<std::true_type, T> ctTtf; // { dg-error "here" } +std::conjunction<std::false_type, T> cfTtf; + +std::disjunction<T> dT; // { dg-error "here" } +std::disjunction<T, std::true_type> dTt; // { dg-error "here" } +std::disjunction<T, std::false_type> dTf; // { dg-error "here" } +std::disjunction<std::false_type, T> dfTtf; // { dg-error "here" } +std::disjunction<std::true_type, T> dtTtf; + +// { dg-prune-output "not convertible to bool|evaluates to false" }
