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

Reply via email to