[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