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@-1 {{in implicit initialization of array element 0 with omitted initializer}} - // expected-note@-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@-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@-15 5{{cannot initialize}} + // expected-error@-15 5{{cannot initialize}} + // expected-error@-15 5{{cannot initialize}} + // + // + // expected-error@-15 5{{cannot initialize}} + // + // expected-error@-15 5{{cannot initialize}} + // + // expected-error@-15 5{{cannot initialize}} + // + // + // expected-error@-15 5{{cannot initialize}} +#else + // expected-error@-29 {{cannot initialize}} + // expected-error@-29 {{cannot initialize}} + // expected-error@-29 {{cannot initialize}} + // + // + // expected-error@-29 {{cannot initialize}} + // + // expected-error@-29 {{cannot initialize}} + // + // expected-error@-29 {{cannot initialize}} + // + // + // expected-error@-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@-13 5{{cannot initialize}} + // + // + // expected-error@-13 5{{cannot initialize}} + // expected-error@-13 5{{cannot initialize}} + // + // expected-error@-13 5{{cannot initialize}} + // + // expected-error@-13 5{{cannot initialize}} + // + // + // expected-error@-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@-5 4{{cannot initialize}} + // expected-error@-5 4{{cannot initialize}} + // expected-error@-5 4{{cannot initialize}} +#else + // expected-error@-8 3{{non-constant-expression cannot be narrowed}} + // expected-error@-8 3{{constant expression evaluates to 1234 which cannot be narrowed}} expected-warning@-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@-5 4{{instantiation of}} + // expected-note@-5 4{{instantiation of}} + // expected-note@-5 4{{instantiation of}} + // expected-note@-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@-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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits