https://bugs.llvm.org/show_bug.cgi?id=42694

            Bug ID: 42694
           Summary: C++20 conditional explicit should be supported in
                    C++14/17 modes
           Product: clang
           Version: trunk
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++2a
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected], [email protected],
                    [email protected], [email protected]

Created attachment 22265
  --> https://bugs.llvm.org/attachment.cgi?id=22265&action=edit
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>

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to