[llvm-bugs] [Bug 42694] New: C++20 conditional explicit should be supported in C++14/17 modes

via llvm-bugs llvm-bugs at lists.llvm.org
Fri Jul 19 19:54:01 PDT 2019


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: unassignedclangbugs at nondot.org
          Reporter: sfinae at hotmail.com
                CC: blitzrakete at gmail.com, erik.pilkington at gmail.com,
                    llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20190720/bf6b9107/attachment.html>


More information about the llvm-bugs mailing list