From d2010991776a26fb1fdc6b2e49cdac1334b7af23 Mon Sep 17 00:00:00 2001 From: Larisse Voufo Date: Sat, 24 Jan 2015 23:09:54 +0000 Subject: [PATCH] First steps in implementing DR1467: List-initialization of aggregate from same-type object. Only the first two items for now, changing Sections 8.5.4 [dcl.init.list] paragraph 3 and 13.3.1.7 [over.match.list] paragraph 1, so that defining class objects and character arrays using uniform initialization syntax is actually treated as list initialization and before it is treated aggregate initialization. llvm-svn: 227022 --- clang/lib/Sema/SemaInit.cpp | 124 +++++++++++++++++++++++++++++++----------- clang/test/CXX/drs/dr14xx.cpp | 123 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+), 32 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 569ef30..e7a8e9c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3222,9 +3222,16 @@ static void TryConstructorInitialization(Sema &S, OverloadCandidateSet::iterator Best; bool AsInitializerList = false; + // C++14 DR 1467 [over.match.list]p1: + // When objects of non-aggregate type T are list-initialized, such that + // 8.5.4 [dcl.init.list] specifies that overload resolution is performed + // according to the rules in this section, overload resolution selects + // the constructor in two phases: + // // C++11 [over.match.list]p1: // When objects of non-aggregate type T are list-initialized, overload // resolution selects the constructor in two phases: + // // - Initially, the candidate functions are the initializer-list // constructors of the class T and the argument list consists of the // initializer list as a single argument. @@ -3425,42 +3432,88 @@ static void TryListInitialization(Sema &S, TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence); return; } - if (DestType->isRecordType()) { - if (S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) { - Sequence.setIncompleteTypeFailure(DestType); - return; - } - // C++11 [dcl.init.list]p3: - // - If T is an aggregate, aggregate initialization is performed. - if (!DestType->isAggregateType()) { - if (S.getLangOpts().CPlusPlus11) { - // - Otherwise, if the initializer list has no elements and T is a - // class type with a default constructor, the object is - // value-initialized. - if (InitList->getNumInits() == 0) { - CXXRecordDecl *RD = DestType->getAsCXXRecordDecl(); - if (RD->hasDefaultConstructor()) { - TryValueInitialization(S, Entity, Kind, Sequence, InitList); - return; - } - } - - // - Otherwise, if T is a specialization of std::initializer_list, - // an initializer_list object constructed [...] - if (TryInitializerListConstruction(S, InitList, DestType, Sequence)) - return; + if (DestType->isRecordType() && + S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) { + Sequence.setIncompleteTypeFailure(DestType); + return; + } - // - Otherwise, if T is a class type, constructors are considered. + // C++14 DR1467 [dcl.init.list]p3: + // - If T is a class type and the initializer list has a single element of + // type cv U, where U is T or a class derived from T, the object is + // initialized from that element (by copy-initialization for + // copy-list-initialization, or by direct-initialization for + // direct-list-initialization). + // - Otherwise, if T is a character array and the initializer list has a + // single element that is an appropriately-typed string literal + // (8.5.2 [dcl.init.string]), initialization is performed as described + // in that section. + // - Otherwise, If T is an aggregate, [...] (continue below). + if (S.getLangOpts().CPlusPlus14 && InitList->getNumInits() == 1) { + if (DestType->isRecordType()) { + QualType InitType = InitList->getInit(0)->getType(); + if (S.Context.hasSameUnqualifiedType(InitType, DestType) || + S.IsDerivedFrom(InitType, DestType)) { Expr *InitListAsExpr = InitList; TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, Sequence, /*InitListSyntax*/true); - } else - Sequence.SetFailed( - InitializationSequence::FK_InitListBadDestinationType); - return; + return; + } + } + if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) { + Expr *SubInit[1] = {InitList->getInit(0)}; + if (!isa(DestAT) && + IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) { + InitializationKind SubKind = + Kind.getKind() == InitializationKind::IK_DirectList + ? InitializationKind::CreateDirect(Kind.getLocation(), + InitList->getLBraceLoc(), + InitList->getRBraceLoc()) + : Kind; + Sequence.InitializeFrom(S, Entity, SubKind, SubInit, + /*TopLevelOfInitList*/ true); + + // TryStringLiteralInitialization() (in InitializeFrom()) will fail if + // the element is not an appropriately-typed string literal, in which + // case we should proceed as in C++11 (below). + if (Sequence) { + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } + } } } + + // C++11 [dcl.init.list]p3: + // - If T is an aggregate, aggregate initialization is performed. + if (DestType->isRecordType() && !DestType->isAggregateType()) { + if (S.getLangOpts().CPlusPlus11) { + // - Otherwise, if the initializer list has no elements and T is a + // class type with a default constructor, the object is + // value-initialized. + if (InitList->getNumInits() == 0) { + CXXRecordDecl *RD = DestType->getAsCXXRecordDecl(); + if (RD->hasDefaultConstructor()) { + TryValueInitialization(S, Entity, Kind, Sequence, InitList); + return; + } + } + + // - Otherwise, if T is a specialization of std::initializer_list, + // an initializer_list object constructed [...] + if (TryInitializerListConstruction(S, InitList, DestType, Sequence)) + return; + + // - Otherwise, if T is a class type, constructors are considered. + Expr *InitListAsExpr = InitList; + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, + Sequence, /*InitListSyntax*/ true); + } else + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + return; + } + if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() && InitList->getNumInits() == 1 && InitList->getInit(0)->getType()->isRecordType()) { @@ -3469,6 +3522,14 @@ static void TryListInitialization(Sema &S, // initialized from that element; if a narrowing conversion is required // to convert the element to T, the program is ill-formed. // + // C++14 DR1467: + // - 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 + // copy-list-initialization, or by direct-initialization for + // direct-list-initialization); if a narrowing conversion is required + // to convert the element to T, the program is ill-formed. + // // Per core-24034, this is direct-initialization if we were performing // direct-list-initialization and copy-initialization otherwise. // We can't use InitListChecker for this, because it always performs @@ -4408,8 +4469,7 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) { /// \brief Determine whether we have compatible array types for the /// purposes of GNU by-copy array initialization. -static bool hasCompatibleArrayTypes(ASTContext &Context, - const ArrayType *Dest, +static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest, const ArrayType *Source) { // If the source and destination array types are equivalent, we're // done. @@ -4668,7 +4728,7 @@ void InitializationSequence::InitializeFrom(Sema &S, return; } - // Determine whether we should consider writeback conversions for + // Determine whether we should consider writeback conversions for // Objective-C ARC. bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount && Entity.isParameterKind(); diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp index e931924..556cc9b 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -195,3 +195,126 @@ namespace dr1460 { // dr1460: 3.5 } #endif } + +#if __cplusplus >= 201103L +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} // std + +namespace dr1467 { + // List-initialization of aggregate from same-type object + + namespace basic0 { + + struct S { + int i = 42; + }; + + S a; + S b(a); + S c{a}; + + struct SS : public S { } x; + S y(x); + S z{x}; + + } // basic0 + + namespace basic1 { + + struct S { + int i{42}; + }; + + S a; + S b(a); + S c{a}; + + struct SS : public S { } x; + S y(x); + S z{x}; + + } // basic1 + + namespace basic2 { + + struct S { + int i = {42}; + }; + + S a; + S b(a); + S c{a}; + + struct SS : public S { } x; + S y(x); + S z{x}; + + } // basic2 + + namespace dr_example { + struct OK { + OK() = default; + OK(const OK&) = default; + OK(int) { } + }; + + OK ok; + OK ok2{ok}; + + + struct X { + X() = default; + X(const X&) = default; + }; + + X x; + X x2{x}; +#if __cplusplus == 201103L + // expected-error@-2 {{excess elements in struct initializer}} +#endif + + // TODO: Only Items 1 and 2 from DR1467 are covered for now. + // Implement remaining items, and expand here as necessary. + + } // dr_example + +} // dr1467 + + +namespace dr1490 { + // List-initialization from a string literal + + char s[4]{"abc"}; // Ok + std::initializer_list{"abc"}; // expected-error {{expected unqualified-id}}} + +} // dr1490 +#endif -- 2.7.4