<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jan 26, 2015 at 11:31 AM, Richard Smith <span dir="ltr"><<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Sat, Jan 24, 2015 at 3:09 PM, Larisse Voufo <<a href="mailto:lvoufo@google.com">lvoufo@google.com</a>> wrote:<br>
> Author: lvoufo<br>
> Date: Sat Jan 24 17:09:54 2015<br>
> New Revision: 227022<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=227022&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=227022&view=rev</a><br>
> Log:<br>
> First steps in implementing DR1467: List-initialization of aggregate from same-type object.<br>
> 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,<br>
> so that defining class objects and character arrays using uniform initialization syntax is actually treated as list initialization<br>
> and before it is treated aggregate initialization.<br>
><br>
> Modified:<br>
> cfe/trunk/lib/Sema/SemaInit.cpp<br>
> cfe/trunk/test/CXX/drs/dr14xx.cpp<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=227022&r1=227021&r2=227022&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=227022&r1=227021&r2=227022&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Sat Jan 24 17:09:54 2015<br>
> @@ -3222,9 +3222,16 @@ static void TryConstructorInitialization<br>
> OverloadCandidateSet::iterator Best;<br>
> bool AsInitializerList = false;<br>
><br>
> + // C++14 DR 1467 [over.match.list]p1:<br>
> + // When objects of non-aggregate type T are list-initialized, such that<br>
> + // 8.5.4 [dcl.init.list] specifies that overload resolution is performed<br>
> + // according to the rules in this section, overload resolution selects<br>
> + // the constructor in two phases:<br>
> + //<br>
> // C++11 [over.match.list]p1:<br>
> // When objects of non-aggregate type T are list-initialized, overload<br>
> // resolution selects the constructor in two phases:<br>
> + //<br>
> // - Initially, the candidate functions are the initializer-list<br>
> // constructors of the class T and the argument list consists of the<br>
> // initializer list as a single argument.<br>
> @@ -3425,42 +3432,88 @@ static void TryListInitialization(Sema &<br>
> TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);<br>
> return;<br>
> }<br>
> - if (DestType->isRecordType()) {<br>
> - if (S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {<br>
> - Sequence.setIncompleteTypeFailure(DestType);<br>
> - return;<br>
> - }<br>
><br>
> - // C++11 [dcl.init.list]p3:<br>
> - // - If T is an aggregate, aggregate initialization is performed.<br>
> - if (!DestType->isAggregateType()) {<br>
> - if (S.getLangOpts().CPlusPlus11) {<br>
> - // - Otherwise, if the initializer list has no elements and T is a<br>
> - // class type with a default constructor, the object is<br>
> - // value-initialized.<br>
> - if (InitList->getNumInits() == 0) {<br>
> - CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();<br>
> - if (RD->hasDefaultConstructor()) {<br>
> - TryValueInitialization(S, Entity, Kind, Sequence, InitList);<br>
> - return;<br>
> - }<br>
> - }<br>
> -<br>
> - // - Otherwise, if T is a specialization of std::initializer_list<E>,<br>
> - // an initializer_list object constructed [...]<br>
> - if (TryInitializerListConstruction(S, InitList, DestType, Sequence))<br>
> - return;<br>
> + if (DestType->isRecordType() &&<br>
> + S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {<br>
> + Sequence.setIncompleteTypeFailure(DestType);<br>
> + return;<br>
> + }<br>
><br>
> - // - Otherwise, if T is a class type, constructors are considered.<br>
> + // C++14 DR1467 [dcl.init.list]p3:<br>
> + // - If T is a class type and the initializer list has a single element of<br>
> + // type cv U, where U is T or a class derived from T, the object is<br>
> + // initialized from that element (by copy-initialization for<br>
> + // copy-list-initialization, or by direct-initialization for<br>
> + // direct-list-initialization).<br>
> + // - Otherwise, if T is a character array and the initializer list has a<br>
> + // single element that is an appropriately-typed string literal<br>
> + // (8.5.2 [dcl.init.string]), initialization is performed as described<br>
> + // in that section.<br>
> + // - Otherwise, If T is an aggregate, [...] (continue below).<br>
> + if (S.getLangOpts().CPlusPlus14 && InitList->getNumInits() == 1) {<br>
<br>
</div></div>This issue is in DR status, so should be applied retroactively to all<br>
standard revisions where it makes sense. In this case, that means it<br>
should apply to C++11 mode as well as C++14 mode.<br></blockquote><div><br></div><div>Ok. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + if (DestType->isRecordType()) {<br>
> + QualType InitType = InitList->getInit(0)->getType();<br>
> + if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||<br>
> + S.IsDerivedFrom(InitType, DestType)) {<br>
> Expr *InitListAsExpr = InitList;<br>
> TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,<br>
> Sequence, /*InitListSyntax*/true);<br>
> - } else<br>
> - Sequence.SetFailed(<br>
> - InitializationSequence::FK_InitListBadDestinationType);<br>
> - return;<br>
> + return;<br>
> + }<br>
> + }<br>
> + if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) {<br>
> + Expr *SubInit[1] = {InitList->getInit(0)};<br>
> + if (!isa<VariableArrayType>(DestAT) &&<br>
> + IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) {<br>
> + InitializationKind SubKind =<br>
> + Kind.getKind() == InitializationKind::IK_DirectList<br>
> + ? InitializationKind::CreateDirect(Kind.getLocation(),<br>
> + InitList->getLBraceLoc(),<br>
> + InitList->getRBraceLoc())<br>
> + : Kind;<br>
> + Sequence.InitializeFrom(S, Entity, SubKind, SubInit,<br>
> + /*TopLevelOfInitList*/ true);<br>
> +<br>
> + // TryStringLiteralInitialization() (in InitializeFrom()) will fail if<br>
> + // the element is not an appropriately-typed string literal, in which<br>
> + // case we should proceed as in C++11 (below).<br>
> + if (Sequence) {<br>
> + Sequence.RewrapReferenceInitList(Entity.getType(), InitList);<br>
> + return;<br>
> + }<br>
> + }<br>
> }<br>
> }<br>
> +<br>
> + // C++11 [dcl.init.list]p3:<br>
> + // - If T is an aggregate, aggregate initialization is performed.<br>
> + if (DestType->isRecordType() && !DestType->isAggregateType()) {<br>
> + if (S.getLangOpts().CPlusPlus11) {<br>
> + // - Otherwise, if the initializer list has no elements and T is a<br>
> + // class type with a default constructor, the object is<br>
> + // value-initialized.<br>
> + if (InitList->getNumInits() == 0) {<br>
> + CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();<br>
> + if (RD->hasDefaultConstructor()) {<br>
> + TryValueInitialization(S, Entity, Kind, Sequence, InitList);<br>
> + return;<br>
> + }<br>
> + }<br>
> +<br>
> + // - Otherwise, if T is a specialization of std::initializer_list<E>,<br>
> + // an initializer_list object constructed [...]<br>
> + if (TryInitializerListConstruction(S, InitList, DestType, Sequence))<br>
> + return;<br>
> +<br>
> + // - Otherwise, if T is a class type, constructors are considered.<br>
> + Expr *InitListAsExpr = InitList;<br>
> + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,<br>
> + Sequence, /*InitListSyntax*/ true);<br>
> + } else<br>
> + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);<br>
> + return;<br>
> + }<br>
> +<br>
> if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&<br>
> InitList->getNumInits() == 1 &&<br>
> InitList->getInit(0)->getType()->isRecordType()) {<br>
> @@ -3469,6 +3522,14 @@ static void TryListInitialization(Sema &<br>
> // initialized from that element; if a narrowing conversion is required<br>
> // to convert the element to T, the program is ill-formed.<br>
> //<br>
> + // C++14 DR1467:<br>
> + // - Otherwise, if the initializer list has a single element of type E<br>
> + // [...references are handled above...], the object or reference is<br>
> + // initialized from that element (by copy-initialization for<br>
> + // copy-list-initialization, or by direct-initialization for<br>
> + // direct-list-initialization); if a narrowing conversion is required<br>
> + // to convert the element to T, the program is ill-formed.<br>
> + //<br>
> // Per core-24034, this is direct-initialization if we were performing<br>
> // direct-list-initialization and copy-initialization otherwise.<br>
> // We can't use InitListChecker for this, because it always performs<br>
> @@ -4408,8 +4469,7 @@ static void checkIndirectCopyRestoreSour<br>
><br>
> /// \brief Determine whether we have compatible array types for the<br>
> /// purposes of GNU by-copy array initialization.<br>
> -static bool hasCompatibleArrayTypes(ASTContext &Context,<br>
> - const ArrayType *Dest,<br>
> +static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest,<br>
> const ArrayType *Source) {<br>
> // If the source and destination array types are equivalent, we're<br>
> // done.<br>
> @@ -4668,7 +4728,7 @@ void InitializationSequence::InitializeF<br>
> return;<br>
> }<br>
><br>
> - // Determine whether we should consider writeback conversions for<br>
> + // Determine whether we should consider writeback conversions for<br>
> // Objective-C ARC.<br>
> bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&<br>
> Entity.isParameterKind();<br>
><br>
> Modified: cfe/trunk/test/CXX/drs/dr14xx.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=227022&r1=227021&r2=227022&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=227022&r1=227021&r2=227022&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/test/CXX/drs/dr14xx.cpp (original)<br>
> +++ cfe/trunk/test/CXX/drs/dr14xx.cpp Sat Jan 24 17:09:54 2015<br>
> @@ -195,3 +195,126 @@ namespace dr1460 { // dr1460: 3.5<br>
> }<br>
> #endif<br>
> }<br>
> +<br>
> +#if __cplusplus >= 201103L<br>
> +namespace std {<br>
> + typedef decltype(sizeof(int)) size_t;<br>
> +<br>
> + // libc++'s implementation<br>
> + template <class _E><br>
> + class initializer_list<br>
> + {<br>
> + const _E* __begin_;<br>
> + size_t __size_;<br>
> +<br>
> + initializer_list(const _E* __b, size_t __s)<br>
> + : __begin_(__b),<br>
> + __size_(__s)<br>
> + {}<br>
> +<br>
> + public:<br>
> + typedef _E value_type;<br>
> + typedef const _E& reference;<br>
> + typedef const _E& const_reference;<br>
> + typedef size_t size_type;<br>
> +<br>
> + typedef const _E* iterator;<br>
> + typedef const _E* const_iterator;<br>
> +<br>
> + initializer_list() : __begin_(nullptr), __size_(0) {}<br>
> +<br>
> + size_t size() const {return __size_;}<br>
> + const _E* begin() const {return __begin_;}<br>
> + const _E* end() const {return __begin_ + __size_;}<br>
> + };<br>
> +} // std<br>
<br>
</div></div>Please put this at the top of the file.<br>
<br>
> +<br>
> +namespace dr1467 {<br>
<br>
This should be marked as " // dr1467: partial c++11" to indicate that<br>
we have partial support for this in trunk, for C++11 onwards. We have<br>
a script (www/make_cxx_dr_status) that automatically generates the<br>
cxx_dr_status page from these comments.<br></blockquote><div><br></div><div>Ok. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + // List-initialization of aggregate from same-type object<br>
> +<br>
> + namespace basic0 {<br>
> +<br>
> + struct S {<br>
> + int i = 42;<br>
> + };<br>
> +<br>
> + S a;<br>
> + S b(a);<br>
> + S c{a};<br>
> +<br>
> + struct SS : public S { } x;<br>
> + S y(x);<br>
> + S z{x};<br>
> +<br>
> + } // basic0<br>
> +<br>
> + namespace basic1 {<br>
> +<br>
> + struct S {<br>
> + int i{42};<br>
> + };<br>
> +<br>
> + S a;<br>
> + S b(a);<br>
> + S c{a};<br>
> +<br>
> + struct SS : public S { } x;<br>
> + S y(x);<br>
> + S z{x};<br>
> +<br>
> + } // basic1<br>
> +<br>
> + namespace basic2 {<br>
> +<br>
> + struct S {<br>
> + int i = {42};<br>
> + };<br>
> +<br>
> + S a;<br>
> + S b(a);<br>
> + S c{a};<br>
> +<br>
> + struct SS : public S { } x;<br>
> + S y(x);<br>
> + S z{x};<br>
> +<br>
> + } // basic2<br>
> +<br>
> + namespace dr_example {<br>
> + struct OK {<br>
> + OK() = default;<br>
> + OK(const OK&) = default;<br>
> + OK(int) { }<br>
> + };<br>
> +<br>
> + OK ok;<br>
> + OK ok2{ok};<br>
> +<br>
> +<br>
> + struct X {<br>
> + X() = default;<br>
> + X(const X&) = default;<br>
> + };<br>
> +<br>
> + X x;<br>
> + X x2{x};<br>
> +#if __cplusplus == 201103L<br>
> + // expected-error@-2 {{excess elements in struct initializer}}<br>
> +#endif<br>
> +<br>
> + // TODO: Only Items 1 and 2 from DR1467 are covered for now.<br>
> + // Implement remaining items, and expand here as necessary.<br>
> +<br>
> + } // dr_example<br>
> +<br>
> +} // dr1467<br>
> +<br>
> +<br>
> +namespace dr1490 {<br>
<br>
</div></div>This should be marked "// dr1490: dup 1467".<br>
<span class=""><br>
> + // List-initialization from a string literal<br>
> +<br>
> + char s[4]{"abc"}; // Ok<br>
> + std::initializer_list<char>{"abc"}; // expected-error {{expected unqualified-id}}}<br>
> +<br>
> +} // dr1490<br>
> +#endif<br>
<br>
</span>Can you add tests for dr1756, 1758, 1631 and 1589 (all resolved by<br>
1467) too, please?<br></blockquote><div><br></div><div>I am still working on these cases. This patch does not handle those yet.</div></div><br></div></div>