From 3c567fce463690d717ca4448c5769524b5a904d8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 12 Feb 2015 01:55:09 +0000 Subject: [PATCH] More for DR1467: In C++, when initializing an element of an aggregate, always use the normal copy-initialization rules. Remove a special case that tries to stay within the list initialization checker here; that makes us do the wrong thing when list-initialization of an aggregate would not perform aggregate initialization. llvm-svn: 228897 --- clang/lib/Sema/SemaInit.cpp | 79 +++++++++++++++++++------------------- clang/test/CXX/drs/dr14xx.cpp | 3 ++ clang/test/SemaCXX/atomic-type.cpp | 11 +++++- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index dab0619..5692d6e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -966,7 +966,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, StructuredList, StructuredIndex); if (InitListExpr *SubInitList = dyn_cast(expr)) { - if (!ElemType->isRecordType() || ElemType->isAggregateType()) { + if (!SemaRef.getLangOpts().CPlusPlus) { InitListExpr *InnerStructuredList = getStructuredSubobjectInit(IList, Index, ElemType, StructuredList, StructuredIndex, @@ -977,8 +977,6 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, ++Index; return; } - assert(SemaRef.getLangOpts().CPlusPlus && - "non-aggregate records are only possible in C++"); // C++ initialization is handled later. } else if (isa(expr)) { // This happens during template instantiation when we see an InitListExpr @@ -991,43 +989,24 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, return; } - // FIXME: Need to handle atomic aggregate types with implicit init lists. - if (ElemType->isScalarType() || ElemType->isAtomicType()) - return CheckScalarType(Entity, IList, ElemType, Index, - StructuredList, StructuredIndex); - - assert((ElemType->isRecordType() || ElemType->isVectorType() || - ElemType->isArrayType()) && "Unexpected type"); - - if (const ArrayType *arrayType = SemaRef.Context.getAsArrayType(ElemType)) { - // arrayType can be incomplete if we're initializing a flexible - // array member. There's nothing we can do with the completed - // type here, though. - - if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { - if (!VerifyOnly) { - CheckStringInit(expr, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); - } - ++Index; - return; - } - - // Fall through for subaggregate initialization. - - } else if (SemaRef.getLangOpts().CPlusPlus) { - // C++ [dcl.init.aggr]p12: - // All implicit type conversions (clause 4) are considered when - // initializing the aggregate member with an initializer from - // an initializer-list. If the initializer can initialize a - // member, the member is initialized. [...] + if (SemaRef.getLangOpts().CPlusPlus) { + // C++ [dcl.init.aggr]p2: + // Each member is copy-initialized from the corresponding + // initializer-clause. // FIXME: Better EqualLoc? InitializationKind Kind = InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); - InitializationSequence Seq(SemaRef, Entity, Kind, expr); + InitializationSequence Seq(SemaRef, Entity, Kind, expr, + /*TopLevelOfInitList*/ true); - if (Seq) { + // C++14 [dcl.init.aggr]p13: + // If the assignment-expression can initialize a member, the member is + // initialized. Otherwise [...] brace elision is assumed + // + // Brace elision is never performed if the element is not an + // assignment-expression. + if (Seq || isa(expr)) { if (!VerifyOnly) { ExprResult Result = Seq.Perform(SemaRef, Entity, Kind, expr); @@ -1042,7 +1021,31 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } // Fall through for subaggregate initialization + } else if (ElemType->isScalarType() || ElemType->isAtomicType()) { + // FIXME: Need to handle atomic aggregate types with implicit init lists. + return CheckScalarType(Entity, IList, ElemType, Index, + StructuredList, StructuredIndex); + } else if (const ArrayType *arrayType = + SemaRef.Context.getAsArrayType(ElemType)) { + // arrayType can be incomplete if we're initializing a flexible + // array member. There's nothing we can do with the completed + // type here, though. + + if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { + if (!VerifyOnly) { + CheckStringInit(expr, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + } + ++Index; + return; + } + + // Fall through for subaggregate initialization. + } else { + assert((ElemType->isRecordType() || ElemType->isVectorType()) && + "Unexpected type"); + // C99 6.7.8p13: // // The initializer for a structure or union object that has @@ -1052,10 +1055,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // initial value of the object, including unnamed members, is // that of the expression. ExprResult ExprRes = expr; - if ((ElemType->isRecordType() || ElemType->isVectorType()) && - SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes, - !VerifyOnly) - != Sema::Incompatible) { + if (SemaRef.CheckSingleAssignmentConstraints( + ElemType, ExprRes, !VerifyOnly) != Sema::Incompatible) { if (ExprRes.isInvalid()) hadError = true; else { diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp index 94e733f..0ffc0ed 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -324,6 +324,9 @@ namespace dr1467 { // dr1467: 3.7 c++11 S s1; S s2 = {s1}; // ok, not list-initialization so we pick the non-explicit constructor } + + struct NestedInit { int a, b, c; }; + NestedInit ni[1] = {{NestedInit{1, 2, 3}}}; } // dr1467 namespace dr1490 { // dr1490: 3.7 c++11 diff --git a/clang/test/SemaCXX/atomic-type.cpp b/clang/test/SemaCXX/atomic-type.cpp index 779b067..a2b314a 100644 --- a/clang/test/SemaCXX/atomic-type.cpp +++ b/clang/test/SemaCXX/atomic-type.cpp @@ -71,6 +71,8 @@ namespace copy_init { #if __cplusplus >= 201103L _Atomic(X) e2{0}; // expected-error {{illegal initializer}} _Atomic(X) a{X(0)}; + // FIXME: This does not seem like the right answer. + _Atomic(int) e3{0}; // expected-error {{illegal initializer}} #endif struct Y { @@ -79,9 +81,14 @@ namespace copy_init { }; Y y1 = { X(0), 4 }; Y y2 = { 0, 4 }; // expected-error {{cannot initialize}} + // FIXME: It's not really clear if we should allow these. Generally, C++11 - // allows extraneous braces around initializers. - Y y3 = { { X(0) }, { 4 } }; // expected-error 2{{illegal initializer type}} + // allows extraneous braces around initializers. We should at least give the + // same answer in all these cases: + Y y3 = { X(0), { 4 } }; // expected-error {{illegal initializer type}} + Y y4 = { { X(0) }, 4 }; + _Atomic(int) ai = { 4 }; // expected-error {{illegal initializer type}} + _Atomic(X) ax = { X(0) }; } bool PR21836(_Atomic(int) *x) { -- 2.7.4