r264564 - P0138R2: Allow direct-list-initialization of an enumeration from an integral
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 27 23:08:38 PDT 2016
Author: rsmith
Date: Mon Mar 28 01:08:37 2016
New Revision: 264564
URL: http://llvm.org/viewvc/llvm-project?rev=264564&view=rev
Log:
P0138R2: Allow direct-list-initialization of an enumeration from an integral
value that can convert to the enum's underlying type.
Added:
cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp
- copied, changed from r264563, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
Removed:
cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Mar 28 01:08:37 2016
@@ -3862,8 +3862,48 @@ static void TryListInitialization(Sema &
}
if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
- InitList->getNumInits() == 1 &&
- InitList->getInit(0)->getType()->isRecordType()) {
+ InitList->getNumInits() == 1) {
+ Expr *E = InitList->getInit(0);
+
+ // - Otherwise, if T is an enumeration with a fixed underlying type,
+ // the initializer-list has a single element v, and the initialization
+ // is direct-list-initialization, the object is initialized with the
+ // value T(v); if a narrowing conversion is required to convert v to
+ // the underlying type of T, the program is ill-formed.
+ auto *ET = DestType->getAs<EnumType>();
+ if (S.getLangOpts().CPlusPlus1z &&
+ Kind.getKind() == InitializationKind::IK_DirectList &&
+ ET && ET->getDecl()->isFixed() &&
+ !S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
+ (E->getType()->isIntegralOrEnumerationType() ||
+ E->getType()->isFloatingType())) {
+ // There are two ways that T(v) can work when T is an enumeration type.
+ // If there is either an implicit conversion sequence from v to T or
+ // a conversion function that can convert from v to T, then we use that.
+ // Otherwise, if v is of integral, enumeration, or floating-point type,
+ // it is converted to the enumeration type via its underlying type.
+ // There is no overlap possible between these two cases (except when the
+ // source value is already of the destination type), and the first
+ // case is handled by the general case for single-element lists below.
+ ImplicitConversionSequence ICS;
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ // If E is of a floating-point type, then the conversion is ill-formed
+ // due to narrowing, but go through the motions in order to produce the
+ // right diagnostic.
+ ICS.Standard.Second = E->getType()->isFloatingType()
+ ? ICK_Floating_Integral
+ : ICK_Integral_Conversion;
+ ICS.Standard.setFromType(E->getType());
+ ICS.Standard.setToType(0, E->getType());
+ ICS.Standard.setToType(1, DestType);
+ ICS.Standard.setToType(2, DestType);
+ Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2),
+ /*TopLevelOfInitList*/true);
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
+
// - Otherwise, if the initializer list has a single element of type E
// [...references are handled above...], the object or reference is
// initialized from that element (by copy-initialization for
@@ -3877,19 +3917,21 @@ static void TryListInitialization(Sema &
// copy-initialization. This only matters if we might use an 'explicit'
// conversion operator, so we only need to handle the cases where the source
// is of record type.
- InitializationKind SubKind =
- Kind.getKind() == InitializationKind::IK_DirectList
- ? InitializationKind::CreateDirect(Kind.getLocation(),
- InitList->getLBraceLoc(),
- InitList->getRBraceLoc())
- : Kind;
- Expr *SubInit[1] = { InitList->getInit(0) };
- Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
- /*TopLevelOfInitList*/true,
- TreatUnavailableAsInvalid);
- if (Sequence)
- Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
- return;
+ if (InitList->getInit(0)->getType()->isRecordType()) {
+ InitializationKind SubKind =
+ Kind.getKind() == InitializationKind::IK_DirectList
+ ? InitializationKind::CreateDirect(Kind.getLocation(),
+ InitList->getLBraceLoc(),
+ InitList->getRBraceLoc())
+ : Kind;
+ Expr *SubInit[1] = { InitList->getInit(0) };
+ Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+ /*TopLevelOfInitList*/true,
+ TreatUnavailableAsInvalid);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
}
InitListChecker CheckInitList(S, Entity, InitList,
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Mar 28 01:08:37 2016
@@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowing
// A narrowing conversion is an implicit conversion ...
QualType FromType = getToType(0);
QualType ToType = getToType(1);
+
+ // A conversion to an enumeration type is narrowing if the conversion to
+ // the underlying type is narrowing. This only arises for expressions of
+ // the form 'Enum{init}'.
+ if (auto *ET = ToType->getAs<EnumType>())
+ ToType = ET->getDecl()->getIntegerType();
+
switch (Second) {
// 'bool' is an integral type; dispatch to the right place to handle it.
case ICK_Boolean_Conversion:
Removed: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp?rev=264563&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (removed)
@@ -1,127 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-
-namespace std {
- typedef decltype(sizeof(int)) size_t;
-
- template <typename E>
- struct initializer_list
- {
- const E *p;
- size_t n;
- initializer_list(const E *p, size_t n) : p(p), n(n) {}
- };
-
- struct string {
- string(const char *);
- };
-
- template<typename A, typename B>
- struct pair {
- pair(const A&, const B&);
- };
-}
-
-namespace bullet1 {
- double ad[] = { 1, 2.0 };
- int ai[] = { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-
- struct S2 {
- int m1;
- double m2, m3;
- };
-
- S2 s21 = { 1, 2, 3.0 };
- S2 s22 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
- S2 s23 { };
-}
-
-namespace bullet4_example1 {
- struct S {
- S(std::initializer_list<double> d) {}
- S(std::initializer_list<int> i) {}
- S() {}
- };
-
- S s1 = { 1.0, 2.0, 3.0 };
- S s2 = { 1, 2, 3 };
- S s3 = { };
-}
-
-namespace bullet4_example2 {
- struct Map {
- Map(std::initializer_list<std::pair<std::string,int>>) {}
- };
-
- Map ship = {{"Sophie",14}, {"Surprise",28}};
-}
-
-namespace bullet4_example3 {
- struct S {
- S(int, double, double) {}
- S() {}
- };
-
- S s1 = { 1, 2, 3.0 };
- S s2 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
- S s3 {};
-}
-
-namespace bullet5 {
- int x1 {2};
- int x2 {2.0}; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-}
-
-namespace bullet6 {
- struct S {
- S(std::initializer_list<double>) {}
- S(const std::string &) {}
- };
-
- const S& r1 = { 1, 2, 3.0 };
- const S& r2 = { "Spinach" };
- S& r3 = { 1, 2, 3 }; // expected-error {{non-const lvalue reference to type 'bullet6::S' cannot bind to an initializer list temporary}}
- const int& i1 = { 1 };
- const int& i2 = { 1.1 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
- const int (&iar)[2] = { 1, 2 };
-}
-
-namespace bullet7 {
- int** pp {};
-}
-
-namespace bullet8 {
- struct A { int i; int j; };
- A a1 { 1, 2 };
- A a2 { 1.2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
-
- struct B {
- B(std::initializer_list<int> i) {}
- };
- B b1 { 1, 2 };
- B b2 { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-
- struct C {
- C(int i, double j) {}
- };
- C c1 = { 1, 2.2 };
- // FIXME: Suppress the narrowing warning in the cases where we issue a narrowing error.
- C c2 = { 1.1, 2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
-
- int j { 1 };
- int k { };
-}
-
-namespace rdar13395022 {
- struct MoveOnly { // expected-note {{candidate}}
- MoveOnly(MoveOnly&&); // expected-note 2{{copy constructor is implicitly deleted because}} expected-note {{candidate}}
- };
-
- void test(MoveOnly mo) {
- auto &&list1 = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'std::initializer_list}}
- MoveOnly (&&list2)[1] = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]'}}
- std::initializer_list<MoveOnly> &&list3 = {};
- MoveOnly (&&list4)[1] = {}; // expected-error {{no matching constructor}}
- // expected-note at -1 {{in implicit initialization of array element 0 with omitted initializer}}
- // expected-note at -2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}
- }
-}
Copied: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp (from r264563, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp?p2=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp&p1=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp&r1=264563&r2=264564&rev=264564&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp Mon Mar 28 01:08:37 2016
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
namespace std {
typedef decltype(sizeof(int)) size_t;
@@ -125,3 +127,128 @@ namespace rdar13395022 {
// expected-note at -2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}
}
}
+
+namespace cxx1z_direct_enum_init {
+ enum A {};
+ enum B : char {};
+ enum class C {};
+ enum class D : char {};
+ enum class E : char { k = 5 };
+
+ template<typename T> void good() {
+ (void)T{0};
+ T t1{0};
+ T t2 = T{0};
+
+ struct S { T t; };
+ S s{T{0}};
+
+ struct U { T t{0}; } u; // expected-note 0+{{instantiation of}}
+
+ struct V { T t; V() : t{0} {} }; // expected-note 0+{{instantiation of}}
+
+ void f(T);
+ f(T{0});
+ }
+#if __cplusplus <= 201402L
+ // expected-error at -15 5{{cannot initialize}}
+ // expected-error at -15 5{{cannot initialize}}
+ // expected-error at -15 5{{cannot initialize}}
+ //
+ //
+ // expected-error at -15 5{{cannot initialize}}
+ //
+ // expected-error at -15 5{{cannot initialize}}
+ //
+ // expected-error at -15 5{{cannot initialize}}
+ //
+ //
+ // expected-error at -15 5{{cannot initialize}}
+#else
+ // expected-error at -29 {{cannot initialize}}
+ // expected-error at -29 {{cannot initialize}}
+ // expected-error at -29 {{cannot initialize}}
+ //
+ //
+ // expected-error at -29 {{cannot initialize}}
+ //
+ // expected-error at -29 {{cannot initialize}}
+ //
+ // expected-error at -29 {{cannot initialize}}
+ //
+ //
+ // expected-error at -29 {{cannot initialize}}
+#endif
+
+ template<typename T> void bad() {
+ T t = {0};
+
+ struct S { T t; };
+ S s1{0};
+ S s2{{0}};
+
+ struct U { T t = {0}; } u; // expected-note 0+{{instantiation of}}
+
+ struct V { T t; V() : t({0}) {} }; // expected-note 0+{{instantiation of}}
+
+ void f(T); // expected-note 0+{{passing argument}}
+ f({0});
+ }
+ // expected-error at -13 5{{cannot initialize}}
+ //
+ //
+ // expected-error at -13 5{{cannot initialize}}
+ // expected-error at -13 5{{cannot initialize}}
+ //
+ // expected-error at -13 5{{cannot initialize}}
+ //
+ // expected-error at -13 5{{cannot initialize}}
+ //
+ //
+ // expected-error at -13 5{{cannot initialize}}
+
+ template<typename T> void ugly() {
+ extern char c;
+ T t1{char('0' + c)};
+ T t2{'0' + c};
+ T t3{1234};
+ }
+#if __cplusplus <= 201402L
+ // expected-error at -5 4{{cannot initialize}}
+ // expected-error at -5 4{{cannot initialize}}
+ // expected-error at -5 4{{cannot initialize}}
+#else
+ // expected-error at -8 3{{non-constant-expression cannot be narrowed}}
+ // expected-error at -8 3{{constant expression evaluates to 1234 which cannot be narrowed}} expected-warning at -8 {{changes value}}
+#endif
+
+ void test() {
+ good<A>(); // expected-note 4{{instantiation of}}
+ good<B>();
+ good<C>();
+ good<D>();
+ good<E>();
+#if __cplusplus <= 201402L
+ // expected-note at -5 4{{instantiation of}}
+ // expected-note at -5 4{{instantiation of}}
+ // expected-note at -5 4{{instantiation of}}
+ // expected-note at -5 4{{instantiation of}}
+#endif
+
+ bad<A>(); // expected-note 4{{instantiation of}}
+ bad<B>(); // expected-note 4{{instantiation of}}
+ bad<C>(); // expected-note 4{{instantiation of}}
+ bad<D>(); // expected-note 4{{instantiation of}}
+ bad<E>(); // expected-note 4{{instantiation of}}
+
+ ugly<B>(); // expected-note {{instantiation of}}
+ ugly<C>(); // ok
+ ugly<D>(); // expected-note {{instantiation of}}
+ ugly<E>(); // expected-note {{instantiation of}}
+#if __cplusplus <= 201402L
+ // expected-note at -4 {{instantiation of}}
+#else
+ (void)B{0.0}; // expected-error {{type 'double' cannot be narrowed}}
+#endif
+ }
+}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Mon Mar 28 01:08:37 2016
@@ -664,7 +664,7 @@ as the draft C++1z standard evolves.</p>
<tr>
<td>Direct-list-initialization of <tt>enum</tt>s</td>
<td><a href="http://wg21.link/p0138r2">P0138R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Hexadecimal floating-point literals</td>
More information about the cfe-commits
mailing list