<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - C++20 conditional explicit should be supported in C++14/17 modes"
   href="https://bugs.llvm.org/show_bug.cgi?id=42694">42694</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>C++20 conditional explicit should be supported in C++14/17 modes
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C++2a
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>sfinae@hotmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=22265" name="attach_22265" title="Test case for conditional explicit">attachment 22265</a> <a href="attachment.cgi?id=22265&action=edit" title="Test case for conditional explicit">[details]</a></span>
Test case for conditional explicit

Like C++17's "if constexpr", C++20's conditional explicit is enormously
valuable to the Standard Library, and we really want to use it in all language
modes. It simplifies our source code and improves build throughput, as we
torment the compiler with fewer constructor overloads to SFINAE away. (It's OK
if it emits a warning that can be locally suppressed, as we've done with
"warning: constexpr if is a C++17 extension [-Wc++17-extensions]".)

C1XX and EDG have recently enabled such "downlevel" support for conditional
explicit; it would be great if Clang 9 also did.

Here's what I observe with Clang 9.0.0-r363781:

C:\Temp>type explicit.cpp
#include <type_traits>
using namespace std;

#pragma warning(disable: 5053) // support for 'explicit(<expr>)' in C++17 and
earlier is a vendor extension


struct No {};
struct Im {};
struct Ex {};

struct A {
    A(Im) {}
    explicit A(Ex) {}
};

template <typename T, typename Arg>
constexpr bool NotConstructible = !is_constructible_v<T, Arg> &&
!is_convertible_v<Arg, T>;

template <typename T, typename Arg>
constexpr bool ImplicitlyConstructible = is_constructible_v<T, Arg> &&
is_convertible_v<Arg, T>;

template <typename T, typename Arg>
constexpr bool ExplicitlyConstructible = is_constructible_v<T, Arg> &&
!is_convertible_v<Arg, T>;

static_assert(NotConstructible<A, No>, "BOOM NotConstructible");
static_assert(ImplicitlyConstructible<A, Im>, "BOOM ImplicitlyConstructible");
static_assert(ExplicitlyConstructible<A, Ex>, "BOOM ExplicitlyConstructible");


template <typename T1, typename T2> struct OldPair {
    template <typename U1, typename U2,
        enable_if_t<conjunction_v<is_constructible<T1, const U1&>,
is_constructible<T2, const U2&>,
            is_convertible<const U1&, T1>, is_convertible<const U2&, T2>>, int>
= 0>
        OldPair(const OldPair<U1, U2>&) {}

    template <typename U1, typename U2,
        enable_if_t<conjunction_v<is_constructible<T1, const U1&>,
is_constructible<T2, const U2&>,
            negation<conjunction<is_convertible<const U1&, T1>,
is_convertible<const U2&, T2>>>>, int> = 0>
        explicit OldPair(const OldPair<U1, U2>&) {}
};

static_assert(NotConstructible<OldPair<A, A>, const OldPair<No, No>&>, "OldPair
BOOM 1");
static_assert(NotConstructible<OldPair<A, A>, const OldPair<No, Im>&>, "OldPair
BOOM 2");
static_assert(NotConstructible<OldPair<A, A>, const OldPair<Im, No>&>, "OldPair
BOOM 3");
static_assert(ImplicitlyConstructible<OldPair<A, A>, const OldPair<Im, Im>&>,
"OldPair BOOM 4");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Im, Ex>&>,
"OldPair BOOM 5");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Ex, Im>&>,
"OldPair BOOM 6");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Ex, Ex>&>,
"OldPair BOOM 7");


template <typename T1, typename T2> struct NewPair {
    template <typename U1, typename U2,
        enable_if_t<conjunction_v<is_constructible<T1, const U1&>,
is_constructible<T2, const U2&>>, int> = 0>
        explicit(!is_convertible_v<const U1&, T1> || !is_convertible_v<const
U2&, T2>)
        NewPair(const NewPair<U1, U2>&) {}
};

static_assert(NotConstructible<NewPair<A, A>, const NewPair<No, No>&>, "NewPair
BOOM 1");
static_assert(NotConstructible<NewPair<A, A>, const NewPair<No, Im>&>, "NewPair
BOOM 2");
static_assert(NotConstructible<NewPair<A, A>, const NewPair<Im, No>&>, "NewPair
BOOM 3");
static_assert(ImplicitlyConstructible<NewPair<A, A>, const NewPair<Im, Im>&>,
"NewPair BOOM 4");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Im, Ex>&>,
"NewPair BOOM 5");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Ex, Im>&>,
"NewPair BOOM 6");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Ex, Ex>&>,
"NewPair BOOM 7");

int main() { }

C:\Temp>cl /EHsc /nologo /W4 /std:c++14 explicit.cpp
explicit.cpp

C:\Temp>cl /EHsc /nologo /W4 /std:c++14 /c /BE explicit.cpp
explicit.cpp

C:\Temp>clang-cl -m32 /EHsc /nologo /W4 /std:c++14 explicit.cpp
explicit.cpp(54,18): error: expected member name or ';' after declaration
specifiers
        explicit(!is_convertible_v<const U1&, T1> || !is_convertible_v<const
U2&, T2>)
        ~~~~~~~~ ^
[...]
6 errors generated.

C:\Temp>clang-cl -m32 /EHsc /nologo /W4 /std:c++17 explicit.cpp
explicit.cpp(54,18): error: expected member name or ';' after declaration
specifiers
        explicit(!is_convertible_v<const U1&, T1> || !is_convertible_v<const
U2&, T2>)
        ~~~~~~~~ ^
[...]
6 errors generated.

C:\Temp>clang-cl -m32 /EHsc /nologo /W4 /std:c++latest explicit.cpp

C:\Temp></pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>