From 80fe8a6c2142df4718e2482a0562ee6142de1685 Mon Sep 17 00:00:00 2001 From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Tue, 3 Jun 2014 08:26:00 +0000 Subject: [PATCH] Implement DR990 and DR1070. Aggregate initialization initializes uninitialized elements from {}, rather than value-initializing them. This permits calling an initializer-list constructor or constructing a std::initializer_list object. (It would also permit initializing a const reference or rvalue reference if that weren't explicitly prohibited by other rules.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210091 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 1 + include/clang/Sema/Initialization.h | 17 +- lib/CodeGen/CGExprCXX.cpp | 29 +-- lib/Sema/SemaInit.cpp | 176 ++++++++++-------- test/CXX/drs/dr10xx.cpp | 33 ++++ test/CXX/drs/dr9xx.cpp | 45 +++++ .../cxx0x-initializer-stdinitializerlist.cpp | 19 +- .../cxx1y-initializer-aggregate.cpp | 2 +- .../SemaCXX/cxx0x-initializer-constructor.cpp | 4 +- .../cxx0x-initializer-stdinitializerlist.cpp | 8 + www/cxx_dr_status.html | 6 +- 11 files changed, 244 insertions(+), 96 deletions(-) create mode 100644 test/CXX/drs/dr10xx.cpp create mode 100644 test/CXX/drs/dr9xx.cpp diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index e0b3c05a662..e8310977be9 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3909,6 +3909,7 @@ public: // Iterators child_range children() { + // FIXME: This does not include the array filler expression. if (InitExprs.empty()) return child_range(); return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); } diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 64e3745dd4f..1b59d2d921e 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -401,6 +401,13 @@ public: return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } + /// \brief If this is an array, vector, or complex number element, get the + /// element's index. + unsigned getElementIndex() const { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + return Index; + } /// \brief If this is already the initializer for an array or vector /// element, sets the element index. void setElementIndex(unsigned Index) { @@ -851,17 +858,17 @@ public: /// /// \param Args the argument(s) provided for initialization. /// - /// \param InInitList true if we are initializing from an expression within - /// an initializer list. This disallows narrowing conversions in C++11 - /// onwards. + /// \param TopLevelOfInitList true if we are initializing from an expression + /// at the top level inside an initializer list. This disallows + /// narrowing conversions in C++11 onwards. InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, - bool InInitList = false); + bool TopLevelOfInitList = false); void InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, - bool InInitList); + bool TopLevelOfInitList); ~InitializationSequence(); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index c6995d8a1b2..762d8e29595 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -858,9 +858,21 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, return true; }; + // If all elements have already been initialized, skip any further + // initialization. + llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements); + if (ConstNum && ConstNum->getZExtValue() <= InitListElements) { + // If there was a Cleanup, deactivate it. + if (CleanupDominator) + DeactivateCleanupBlock(Cleanup, CleanupDominator); + return; + } + + assert(Init && "have trailing elements to initialize but no initializer"); + // If this is a constructor call, try to optimize it out, and failing that // emit a single loop to initialize all remaining elements. - if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){ + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { CXXConstructorDecl *Ctor = CCE->getConstructor(); if (Ctor->isTrivial()) { // If new expression did not specify value-initialization, then there @@ -891,7 +903,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, // If this is value-initialization, we can usually use memset. ImplicitValueInitExpr IVIE(ElementType); - if (Init && isa<ImplicitValueInitExpr>(Init)) { + if (isa<ImplicitValueInitExpr>(Init)) { if (TryMemsetInitialization()) return; @@ -906,15 +918,10 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) && "got wrong type of element to initialize"); - llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements); - - // If all elements have already been initialized, skip the whole loop. - if (ConstNum && ConstNum->getZExtValue() <= InitListElements) { - // If there was a Cleanup, deactivate it. - if (CleanupDominator) - DeactivateCleanupBlock(Cleanup, CleanupDominator); - return; - } + // If we have an empty initializer list, we can usually use memset. + if (auto *ILE = dyn_cast<InitListExpr>(Init)) + if (ILE->getNumInits() == 0 && TryMemsetInitialization()) + return; // Create the loop blocks. llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index db811456e2e..e3225da7f71 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -312,15 +312,20 @@ class InitListChecker { int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); - void FillInValueInitForField(unsigned Init, FieldDecl *Field, + static ExprResult PerformEmptyInit(Sema &SemaRef, + SourceLocation Loc, + const InitializedEntity &Entity, + bool VerifyOnly); + void FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, bool &RequiresSecondPass); - void FillInValueInitializations(const InitializedEntity &Entity, + void FillInEmptyInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass); bool CheckFlexibleArrayInit(const InitializedEntity &Entity, Expr *InitExpr, FieldDecl *Field, bool TopLevelObject); - void CheckValueInitializable(const InitializedEntity &Entity); + void CheckEmptyInitializable(const InitializedEntity &Entity, + SourceLocation Loc); public: InitListChecker(Sema &S, const InitializedEntity &Entity, @@ -333,33 +338,84 @@ public: }; } // end anonymous namespace -void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) { - assert(VerifyOnly && - "CheckValueInitializable is only inteded for verification mode."); - - SourceLocation Loc; +ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, + SourceLocation Loc, + const InitializedEntity &Entity, + bool VerifyOnly) { InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, Entity, Kind, None); - if (InitSeq.Failed()) + MultiExprArg SubInit; + Expr *InitExpr; + InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc); + + // C++ [dcl.init.aggr]p7: + // If there are fewer initializer-clauses in the list than there are + // members in the aggregate, then each member not explicitly initialized + // ... + if (SemaRef.getLangOpts().CPlusPlus11 && + Entity.getType()->getBaseElementTypeUnsafe()->isRecordType()) { + // C++1y / DR1070: + // shall be initialized [...] from an empty initializer list. + // + // We apply the resolution of this DR to C++11 but not C++98, since C++98 + // does not have useful semantics for initialization from an init list. + // We treat this as copy-initialization, because aggregate initialization + // always performs copy-initialization on its elements. + // + // Only do this if we're initializing a class type, to avoid filling in + // the initializer list where possible. + InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context) + InitListExpr(SemaRef.Context, Loc, None, Loc); + InitExpr->setType(SemaRef.Context.VoidTy); + SubInit = InitExpr; + Kind = InitializationKind::CreateCopy(Loc, Loc); + } else { + // C++03: + // shall be value-initialized. + } + + InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit); + if (!InitSeq) { + if (!VerifyOnly) { + InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit); + if (Entity.getKind() == InitializedEntity::EK_Member) + SemaRef.Diag(Entity.getDecl()->getLocation(), + diag::note_in_omitted_aggregate_initializer) + << /*field*/1 << Entity.getDecl(); + else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) + SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer) + << /*array element*/0 << Entity.getElementIndex(); + } + return ExprError(); + } + + return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr)) + : InitSeq.Perform(SemaRef, Entity, Kind, SubInit); +} + +void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, + SourceLocation Loc) { + assert(VerifyOnly && + "CheckEmptyInitializable is only inteded for verification mode."); + if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true).isInvalid()) hadError = true; } -void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, +void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, bool &RequiresSecondPass) { - SourceLocation Loc = ILE->getLocStart(); + SourceLocation Loc = ILE->getLocEnd(); unsigned NumInits = ILE->getNumInits(); InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { - // If there's no explicit initializer but we have a default initializer, use - // that. This only happens in C++1y, since classes with default - // initializers are not aggregates in C++11. + // C++1y [dcl.init.aggr]p7: + // If there are fewer initializer-clauses in the list than there are + // members in the aggregate, then each member not explicitly initialized + // shall be initialized from its brace-or-equal-initializer [...] if (Field->hasInClassInitializer()) { - Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, - ILE->getRBraceLoc(), Field); + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, Loc, Field); if (Init < NumInits) ILE->setInit(Init, DIE); else { @@ -369,9 +425,6 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, return; } - // FIXME: We probably don't need to handle references - // specially here, since value-initialization of references is - // handled in InitializationSequence. if (Field->getType()->isReferenceType()) { // C++ [dcl.init.aggr]p9: // If an incomplete or empty initializer-list leaves a @@ -386,20 +439,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, return; } - InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, - true); - InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, None); - if (!InitSeq) { - InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None); - SemaRef.Diag(Field->getLocation(), - diag::note_in_omitted_aggregate_initializer) - << /*field*/1 << Field; - hadError = true; - return; - } - - ExprResult MemberInit - = InitSeq.Perform(SemaRef, MemberEntity, Kind, None); + ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity, + /*VerifyOnly*/false); if (MemberInit.isInvalid()) { hadError = true; return; @@ -409,8 +450,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, MemberInit.getAs<Expr>()); - } else if (InitSeq.isConstructorInitialization()) { - // Value-initialization requires a constructor call, so + } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) { + // Empty initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. @@ -419,7 +460,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, } } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) - FillInValueInitializations(MemberEntity, InnerILE, + FillInEmptyInitializations(MemberEntity, InnerILE, RequiresSecondPass); } @@ -427,7 +468,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, /// with expressions that perform value-initialization of the /// appropriate type. void -InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, +InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass) { assert((ILE->getType() != SemaRef.Context.VoidTy) && @@ -436,13 +477,13 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { const RecordDecl *RDecl = RType->getDecl(); if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) - FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), + FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass); else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { for (auto *Field : RDecl->fields()) { if (Field->hasInClassInitializer()) { - FillInValueInitForField(0, Field, Entity, ILE, RequiresSecondPass); + FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass); break; } } @@ -455,7 +496,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (hadError) return; - FillInValueInitForField(Init, Field, Entity, ILE, RequiresSecondPass); + FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass); if (hadError) return; @@ -489,10 +530,6 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, } else ElementType = ILE->getType(); - SourceLocation Loc = ILE->getLocEnd(); - if (ILE->getSyntacticForm()) - Loc = ILE->getSyntacticForm()->getLocEnd(); - for (unsigned Init = 0; Init != NumElements; ++Init) { if (hadError) return; @@ -503,19 +540,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); if (!InitExpr && !ILE->hasArrayFiller()) { - InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, - true); - InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, None); - if (!InitSeq) { - InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None); - SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer) - << /*array element*/0 << Init; - hadError = true; - return; - } - - ExprResult ElementInit - = InitSeq.Perform(SemaRef, ElementEntity, Kind, None); + ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(), + ElementEntity, + /*VerifyOnly*/false); if (ElementInit.isInvalid()) { hadError = true; return; @@ -538,8 +565,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, return; } - if (InitSeq.isConstructorInitialization()) { - // Value-initialization requires a constructor call, so + if (!isa<ImplicitValueInitExpr>(ElementInit.get())) { + // Empty initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. @@ -549,7 +576,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, } } else if (InitListExpr *InnerILE = dyn_cast_or_null<InitListExpr>(InitExpr)) - FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass); + FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass); } } @@ -567,9 +594,9 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, if (!hadError && !VerifyOnly) { bool RequiresSecondPass = false; - FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); + FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass); if (RequiresSecondPass && !hadError) - FillInValueInitializations(Entity, FullyStructuredList, + FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass); } } @@ -678,7 +705,6 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, InitListExpr *IList, QualType &T, InitListExpr *StructuredList, bool TopLevelObject) { - assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); if (!VerifyOnly) { SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); @@ -1121,8 +1147,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, if (Index >= IList->getNumInits()) { // Make sure the element type can be value-initialized. if (VerifyOnly) - CheckValueInitializable( - InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity)); + CheckEmptyInitializable( + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), + IList->getLocEnd()); return; } @@ -1169,7 +1196,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) { if (VerifyOnly) - CheckValueInitializable(ElementEntity); + CheckEmptyInitializable(ElementEntity, IList->getLocEnd()); break; } @@ -1346,8 +1373,9 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // If so, check if doing that is possible. // FIXME: This needs to detect holes left by designated initializers too. if (maxElementsKnown && elementIndex < maxElements) - CheckValueInitializable(InitializedEntity::InitializeElement( - SemaRef.Context, 0, Entity)); + CheckEmptyInitializable(InitializedEntity::InitializeElement( + SemaRef.Context, 0, Entity), + IList->getLocEnd()); } } @@ -1432,8 +1460,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, Field != FieldEnd; ++Field) { if (Field->getDeclName()) { if (VerifyOnly) - CheckValueInitializable( - InitializedEntity::InitializeMember(*Field, &Entity)); + CheckEmptyInitializable( + InitializedEntity::InitializeMember(*Field, &Entity), + IList->getLocEnd()); else StructuredList->setInitializedFieldInUnion(*Field); break; @@ -1545,8 +1574,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // FIXME: Should check for holes left by designated initializers too. for (; Field != FieldEnd && !hadError; ++Field) { if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) - CheckValueInitializable( - InitializedEntity::InitializeMember(*Field, &Entity)); + CheckEmptyInitializable( + InitializedEntity::InitializeMember(*Field, &Entity), + IList->getLocEnd()); } } diff --git a/test/CXX/drs/dr10xx.cpp b/test/CXX/drs/dr10xx.cpp new file mode 100644 index 00000000000..64c71b2b0f9 --- /dev/null +++ b/test/CXX/drs/dr10xx.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors + +// expected-no-diagnostics + +namespace std { + __extension__ typedef __SIZE_TYPE__ size_t; + + template<typename T> struct initializer_list { + const T *p; size_t n; + initializer_list(const T *p, size_t n); + }; +} + +namespace dr1070 { // dr1070: 3.5 +#if __cplusplus >= 201103L + struct A { + A(std::initializer_list<int>); + }; + struct B { + int i; + A a; + }; + B b = {1}; + struct C { + std::initializer_list<int> a; + B b; + std::initializer_list<double> c; + }; + C c = {}; +#endif +} diff --git a/test/CXX/drs/dr9xx.cpp b/test/CXX/drs/dr9xx.cpp new file mode 100644 index 00000000000..40dc2821adc --- /dev/null +++ b/test/CXX/drs/dr9xx.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors + +#if __cplusplus < 201103L +// expected-no-diagnostics +#endif + +namespace std { + __extension__ typedef __SIZE_TYPE__ size_t; + + template<typename T> struct initializer_list { + const T *p; size_t n; + initializer_list(const T *p, size_t n); + }; +} + +namespace dr990 { // dr990: 3.5 +#if __cplusplus >= 201103L + struct A { // expected-note 2{{candidate}} + A(std::initializer_list<int>); // expected-note {{candidate}} + }; + struct B { + A a; + }; + B b1 { }; + B b2 { 1 }; // expected-error {{no viable conversion from 'int' to 'dr990::A'}} + B b3 { { 1 } }; + + struct C { + C(); + C(int); + C(std::initializer_list<int>) = delete; // expected-note {{here}} + }; + C c1[3] { 1 }; // ok + C c2[3] { 1, {2} }; // expected-error {{call to deleted}} + + struct D { + D(); + D(std::initializer_list<int>); + D(std::initializer_list<double>); + }; + D d{}; +#endif +} diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index 4bc24e88be4..9c8d7f1196f 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s namespace std { typedef decltype(sizeof(int)) size_t; @@ -431,3 +431,20 @@ namespace nested { // CHECK: } } } + +namespace DR1070 { + struct A { + A(std::initializer_list<int>); + }; + struct B { + int i; + A a; + }; + B b = {1}; + struct C { + std::initializer_list<int> a; + B b; + std::initializer_list<double> c; + }; + C c = {}; +} diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp index ae49a047f62..8bdf8633d61 100644 --- a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp +++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp @@ -46,7 +46,7 @@ B z { 1 }; // CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @a, i32 0, i32 2) // CHECK: call i32 @_ZN1A1fEv({{.*}} @a) // CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3) -// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4)) +// CHECK: store double 1.000000e+00, double* getelementptr inbounds ({{.*}} @a, i32 0, i32 4, i32 0) // No dynamic initialization of 'b': diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index 2dea40c0bd4..3ea53095d4e 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -389,8 +389,8 @@ namespace PR11410 { struct B { A a; // expected-note {{in implicit initialization of field 'a'}} - } b = { // expected-error {{call to deleted constructor}} - }; + } b = { + }; // expected-error {{call to deleted constructor}} struct C { C(int = 0); // expected-note 2{{candidate}} diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index 9d89cce67b3..db6614de037 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -230,3 +230,11 @@ namespace PR18013 { int f(); std::initializer_list<long (*)()> x = {f}; // expected-error {{cannot initialize an array element of type 'long (*const)()' with an lvalue of type 'int ()': different return type ('long' vs 'int')}} } + +namespace DR1070 { + struct S { + S(std::initializer_list<int>); + }; + S s[3] = { {1, 2, 3}, {4, 5} }; // ok + S *p = new S[3] { {1, 2, 3}, {4, 5} }; // ok +} diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 79790131c22..d3503c7a2b4 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -3233,7 +3233,7 @@ of class templates</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532">532</a></td> <td>C++11</td> <td>Member/nonmember operator template partial ordering</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="533"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#533">533</a></td> @@ -5755,7 +5755,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990">990</a></td> <td>CD2</td> <td>Value initialization with multiple initializer-list constructors</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="991"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#991">991</a></td> @@ -6235,7 +6235,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1070">1070</a></td> <td>C++11</td> <td>Missing initializer clauses in aggregate initialization</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="1071"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1071">1071</a></td> -- GitLab