<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/54803>54803</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            std::conjunction and std::disjunction implementations don't implement less obvious standard requirements
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          jacobsa
      </td>
    </tr>
</table>

<pre>
    Here are some conformance tests for behavior specified for `std::conjunction` and `std::disjunction` in [[meta.logical]](https://timsong-cpp.github.io/cppwp/n4659/meta.logical#lib:disjunction) by N4659 (C++17). In particular they exercise the following:

* The requirement that the type traits inherit from an input type.
* The requirement that the type traits be usable with integral constants for which `bool(Bi::value)` is valid even if `value` is not a `bool`.
* The clauses that say `value` need not be present for later inputs in the event of short-circuiting.

```c++
// Weird false/true types that aren't actually bool constants (but should still
// be legal according to [meta.logical] because `bool(T::value)` is valid), are
// distinct from std::false_type and std::true_type, and are distinct from other
// instantiations of the same template.
//
// These let us check finicky details mandated by the standard like
// "std::conjunction should evaluate to a type that inherits from the first
// false-y input".
template <int>
struct MyFalse : std::integral_constant<int, 0> {};

template <int>
struct MyTrue : std::integral_constant<int, -1> {};

/////////////////////
// std::conjunction
/////////////////////

// Base case: always true.
static_assert(std::is_base_of_v<std::true_type, std::conjunction<>>);

// One predicate: inherits from that predicate, regardless of value.
static_assert(std::is_base_of_v<MyFalse<0>, std::conjunction<MyFalse<0>>>);

static_assert(std::is_base_of_v<MyTrue<0>, std::conjunction<MyTrue<0>>>);

// Multiple predicates, with at least one false: inherits from that one.
static_assert(std::is_base_of_v<
              MyFalse<1>, std::conjunction<MyTrue<0>, MyFalse<1>, MyTrue<2>>>);

static_assert(std::is_base_of_v<
              MyFalse<1>, std::conjunction<MyTrue<0>, MyFalse<1>, MyFalse<2>>>);

// Short circuiting: in the case above, additional predicates need not even
// define a value member.
struct Empty {};
static_assert(std::is_base_of_v<
              MyFalse<1>, std::conjunction<MyTrue<0>, MyFalse<1>, Empty>>);

// All predicates true: inherits from the last.
static_assert(std::is_base_of_v<
              MyTrue<2>, std::conjunction<MyTrue<0>, MyTrue<1>, MyTrue<2>>>);

/////////////////////
// std::disjunction
/////////////////////

// Base case: always false.
static_assert(std::is_base_of_v<std::false_type, std::disjunction<>>);

// One predicate: inherits from that predicate, regardless of value.
static_assert(std::is_base_of_v<MyFalse<0>, std::disjunction<MyFalse<0>>>);

static_assert(std::is_base_of_v<MyTrue<0>, std::disjunction<MyTrue<0>>>);

// Multiple predicates, with at least one true: inherits from that one.
static_assert(std::is_base_of_v<
              MyTrue<1>, std::disjunction<MyFalse<0>, MyTrue<1>, MyFalse<2>>>);

static_assert(std::is_base_of_v<
              MyTrue<1>, std::disjunction<MyFalse<0>, MyTrue<1>, MyTrue<2>>>);

// Short circuiting: in the case above, additional predicates need not even
// define a value member.
static_assert(std::is_base_of_v<
              MyTrue<1>, std::disjunction<MyFalse<0>, MyTrue<1>, Empty>>);

// All predicates false: inherits from the last.
static_assert(
    std::is_base_of_v<MyFalse<2>,
                      std::disjunction<MyFalse<0>, MyFalse<1>, MyFalse<2>>>);
```

The implementations in libc++ fail basically all of these tests, apparently because they only ever evaluate to `std::false_type` or `std::true_type` rather than something that inherits from an input as the standard requires. Even after fixing that I believe there are also problems with short-circuiting in both cases, and with failing to treat `-1` as `true` in at least the case of `std::conjunction`.

I tested this using the version as of [`8a2a9665`](https://github.com/llvm/llvm-project/blob/8a2a966520023cd7d424e89b730c054f1f06f496/libcxx/include/type_traits), in C++17 mode using Google's internal build system.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzVWEtz2zYQ_jXSBWMOTVGSddDBj7jNIe2hmelRA4KghAQkWAC0rX_fb0FKImXZsTJOmnpoisRjsfvti7uZybfL36WVjOPfmVIyYarC2JJXQjIvnXcMryyTG_6g8OBqKVShZB6GR7PY-Xw0ucaFjV-aSnhlKgwzXuWD6Vy5_rSq2Gh6g6uUnkfarJXgejS9oyu52nhfO9qX3OPyqnSmWl-Iuo7Wym-aLFIG43h_rPFbpbPpAr8DUslEq-zo3GTBsi37g5YznHI7Sm5wXc4xEbGPFau59Uo0mlvmN3LL5JO0QjlJb5BXa_OoqjXxFd-N4t09uWafMW_lP42yspSVx3ruwya_rXGzXAFHVW2kVZ4V1pSAB-9148OK6ExKmWSN45mW7BFwgJCXa8s16c55XnU6e9wosSEdZMYAj6sb1WrigetGQuSgBsfwqnImHyQ4Kmh5O99OVsYzvqcxi484FZo3TrqWS8e3g-2VhJUQAbBbW-lIHOJLcy9tKz2BEqSj4z0zBXMbY_2FUFY0ygPsaAD1LG4v0WpuxwwZCftbKgur5NpJshnbtJh1zMG-of85HoRvuNZbRhL1EANAGdSB8xudM-eV1gPyEELLNUDmQhibgzXmDXtuwFgoCJQe8J9fxp1ek1vibnAYjBbCi85W9j4UhFsFSyD32o-TsGE40MIMefOQhgHKdnCGaiVXnFzDEfakCMdL8vuyJi1F_Q2DzVC-I0A8DJGJjRRfWaEqJb5uWQ48lHYMISQHjZxcLlD2NAAVafV1KO0oSU5FkZ0uJAEHSoQ37_yAVNr5k2sFDC6qrPMD0gGxi21rbTink2gnIBtNbuE9o8mHdtwBSSD2aXtP-zB7fQB552Wrnc10ewF5DAJsNL8Zze9Gk5u-xX7zoM9kp2895-LyxYM6HX331QftZEh_x1P6Z91w4CxwIwy4fuRbOCwwiXY4wTzFijsnLSC4OqDkVhl2rUyxegBAp13hpCCTW9ICLrjeKQzZn1WIVzkc2ge2jg0NtneYxzEWccHmWrrgRcHNz2S_Mzg8xYGzF1k_WviCIG8_lszvLaf2172O3qdGe1XrHoSOKIdEBeC05A6BHhC3kfo0vJg_E8F2NRv8HcC6PEc-rHu-c78keQfcfzyzu5HXuO0U9hdlXHbIuK1KQjwlv2Q8Mw9tYslzRTwgBx50e8jylMKHSUwiJWB_6xGslGUmbTSIfx_K2m-PA9qvgmJg7hvgXesBGD7QfG7SSJUw-3cx6b4ZniVeN3CWQf-QrNL_Iv-JWSXEm-9NK4cvrwHofVH-Z3llyPrPyivHp_6AvPKSD75jWjlypbdhetoJ3xKofxlm3xwx_quk8kvg9B1548VvoVcTx0GOb_t_ly9Oib77O0Pisz84doV7HwpqICiUR6HR0VWhsBGtsq68ByxKM8hDpTUqdty6MtV1valgQXVNxb2nkr4rvUPzxlQYgf3YQQHZb0n1gjpK8qN21qGQwJzlVD5TEKlCl8xvQv3_vArdt3W4Gxa9XU_HRewDdVp4QT2QQj3t6XwE91qBX9rXNeTAn4GZmAwYuTbUHfdHCLEMxX1wK7er_8NSQq9rU3grcQQkQQVJvTlHzyFQtq24fQDdO6gpXmnuDZoyH4Mq4K8AxbHGtRJJBuQdVfE8ZC9q9s3iK57wxWw2JUs40ejrmnvClHjR-mH3cwEMvkgBm7_PtMnwsyOUxHEyEfk8T5NUXi2y-SQW8TQtLot4VqSLGRGAPT094UFVQjd5aA5Brau2l9Y1YIDBvhvISpPLTpDfjFlrbJm70GWzFKeyRlGHaAuhy2icLyf5YrLgY6-8lsuTjYxBs6bnXc_MPzdtk2o_ztrsnz0o07hn1kQr3Lixenk2jsq5huzlfppexZPxZsln6WWSFjzleZLN40supnIWx2ki6GGejTWHgbpl6NrejdUyiZMkTuM5boskjSZxscgWCz5PZum0EGKUxrKEBUZ0cGTsemyXgYesWTtMagX_PUwiqKk1wv6OPm88LH35hQuTOT4O7C4Dr_8CSRPzkA">