From 10f04a6267eb07d3be00db1fd0369e1398f5d0a8 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 22 Dec 2011 14:44:04 +0000 Subject: [PATCH] List-initialization via constructor part 1. Still needs: pretty-printing, overloading, initializer_list. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147145 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Initialization.h | 7 +- lib/Sema/SemaInit.cpp | 522 ++++++++++-------- .../dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp | 34 +- test/SemaCXX/aggregate-initialization.cpp | 22 +- .../SemaCXX/cxx0x-initializer-constructor.cpp | 66 +++ 5 files changed, 402 insertions(+), 249 deletions(-) create mode 100644 test/SemaCXX/cxx0x-initializer-constructor.cpp diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 99bed038f1..ba161c4f11 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -825,18 +825,19 @@ public: void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, QualType T); - /// \brief Add a list-initialiation step. + /// \brief Add a list-initialization step. void AddListInitializationStep(QualType T); /// \brief Add a constructor-initialization step. void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, AccessSpecifier Access, QualType T, - bool HadMultipleCandidates); + bool HadMultipleCandidates, + bool FromInitList); /// \brief Add a zero-initialization step. void AddZeroInitializationStep(QualType T); - + /// \brief Add a C assignment step. // // FIXME: It isn't clear whether this should ever be needed; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7dbf830431..ad29bce8ac 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2701,9 +2701,10 @@ InitializationSequence ::AddConstructorInitializationStep(CXXConstructorDecl *Constructor, AccessSpecifier Access, QualType T, - bool HadMultipleCandidates) { + bool HadMultipleCandidates, + bool FromInitList) { Step S; - S.Kind = SK_ConstructorInitialization; + S.Kind = FromInitList ? SK_ListConstructorCall : SK_ConstructorInitialization; S.Type = T; S.Function.HadMultipleCandidates = HadMultipleCandidates; S.Function.Function = Constructor; @@ -2815,6 +2816,178 @@ static void MaybeProduceObjCObject(Sema &S, } } +/// \brief When initializing from init list via constructor, deal with the +/// empty init list and std::initializer_list special cases. +/// +/// \return True if this was a special case, false otherwise. +static bool TryListConstructionSpecialCases(Sema &S, + Expr **Args, unsigned NumArgs, + CXXRecordDecl *DestRecordDecl, + QualType DestType, + InitializationSequence &Sequence) { + // C++0x [dcl.init.list]p3: + // List-initialization of an object of type T is defined as follows: + // - If the initializer list has no elements and T is a class type with + // a default constructor, the object is value-initialized. + if (NumArgs == 0) { + if (CXXConstructorDecl *DefaultConstructor = + S.LookupDefaultConstructor(DestRecordDecl)) { + if (DefaultConstructor->isDeleted() || + S.isFunctionConsideredUnavailable(DefaultConstructor)) { + // Fake an overload resolution failure. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + DeclAccessPair FoundDecl = DeclAccessPair::make(DefaultConstructor, + DefaultConstructor->getAccess()); + if (FunctionTemplateDecl *ConstructorTmpl = + dyn_cast(DefaultConstructor)) + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + /*ExplicitArgs*/ 0, + Args, NumArgs, CandidateSet, + /*SuppressUserConversions*/ false); + else + S.AddOverloadCandidate(DefaultConstructor, FoundDecl, + Args, NumArgs, CandidateSet, + /*SuppressUserConversions*/ false); + Sequence.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + OR_Deleted); + } else + Sequence.AddConstructorInitializationStep(DefaultConstructor, + DefaultConstructor->getAccess(), + DestType, + /*MultipleCandidates=*/false, + /*FromInitList=*/true); + return true; + } + } + + // - Otherwise, if T is a specialization of std::initializer_list, [...] + // FIXME: Implement. + + // Not a special case. + return false; +} + +/// \brief Attempt initialization by constructor (C++ [dcl.init]), which +/// enumerates the constructors of the initialized entity and performs overload +/// resolution to select the best. +/// If FromInitList is true, this is list-initialization of a non-aggregate +/// class type. +static void TryConstructorInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs, + QualType DestType, + InitializationSequence &Sequence, + bool FromInitList = false) { + // Check constructor arguments for self reference. + if (DeclaratorDecl *DD = Entity.getDecl()) + // Parameters arguments are occassionially constructed with itself, + // for instance, in recursive functions. Skip them. + if (!isa(DD)) + for (unsigned i = 0; i < NumArgs; ++i) + S.CheckSelfReference(DD, Args[i]); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value || + Kind.getKind() == InitializationKind::IK_Default); + + // The type we're constructing needs to be complete. + if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + Sequence.SetFailed(InitializationSequence::FK_Incomplete); + } + + const RecordType *DestRecordType = DestType->getAs(); + assert(DestRecordType && "Constructor initialization requires record type"); + CXXRecordDecl *DestRecordDecl + = cast(DestRecordType->getDecl()); + + if (FromInitList && + TryListConstructionSpecialCases(S, Args, NumArgs, DestRecordDecl, + DestType, Sequence)) + return; + + // - Otherwise, if T is a class type, constructors are considered. The + // applicable constructors are enumerated, and the best one is chosen + // through overload resolution. + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); + Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + bool SuppressUserConversions = false; + + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl = dyn_cast(D); + if (ConstructorTmpl) + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + else { + Constructor = cast(D); + + // If we're performing copy initialization using a copy constructor, we + // suppress user-defined conversions on the arguments. + // FIXME: Move constructors? + if (Kind.getKind() == InitializationKind::IK_Copy && + Constructor->isCopyConstructor()) + SuppressUserConversions = true; + } + + if (!Constructor->isInvalidDecl() && + (AllowExplicit || !Constructor->isExplicit())) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + /*ExplicitArgs*/ 0, + Args, NumArgs, CandidateSet, + SuppressUserConversions); + else + S.AddOverloadCandidate(Constructor, FoundDecl, + Args, NumArgs, CandidateSet, + SuppressUserConversions); + } + } + + SourceLocation DeclLoc = Kind.getLocation(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + Result); + return; + } + + // C++0x [dcl.init]p6: + // If a program calls for the default initialization of an object + // of a const-qualified type T, T shall be a class type with a + // user-provided default constructor. + if (Kind.getKind() == InitializationKind::IK_Default && + Entity.getType().isConstQualified() && + cast(Best->Function)->isImplicit()) { + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + return; + } + + // Add the constructor initialization step. Any cv-qualification conversion is + // subsumed by the initialization. + bool HadMultipleCandidates = (CandidateSet.size() > 1); + CXXConstructorDecl *CtorDecl = cast(Best->Function); + Sequence.AddConstructorInitializationStep(CtorDecl, + Best->FoundDecl.getAccess(), + DestType, HadMultipleCandidates, + FromInitList); +} + static bool ResolveOverloadedFunctionForReferenceBinding(Sema &S, Expr *Initializer, @@ -2942,9 +3115,13 @@ static void TryListInitialization(Sema &S, TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence); return; } - // FIXME: C++11 defines behavior for this case. if (DestType->isRecordType() && !DestType->isAggregateType()) { - Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + if (S.getLangOptions().CPlusPlus0x) + TryConstructorInitialization(S, Entity, Kind, InitList->getInits(), + InitList->getNumInits(), DestType, Sequence, + /*FromInitList=*/true); + else + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); return; } @@ -3420,117 +3597,6 @@ static void TryStringLiteralInitialization(Sema &S, Sequence.AddStringInitStep(Entity.getType()); } -/// \brief Attempt initialization by constructor (C++ [dcl.init]), which -/// enumerates the constructors of the initialized entity and performs overload -/// resolution to select the best. -static void TryConstructorInitialization(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr **Args, unsigned NumArgs, - QualType DestType, - InitializationSequence &Sequence) { - // Check constructor arguments for self reference. - if (DeclaratorDecl *DD = Entity.getDecl()) - // Parameters arguments are occassionially constructed with itself, - // for instance, in recursive functions. Skip them. - if (!isa(DD)) - for (unsigned i = 0; i < NumArgs; ++i) - S.CheckSelfReference(DD, Args[i]); - - // Build the candidate set directly in the initialization sequence - // structure, so that it will persist if we fail. - OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); - CandidateSet.clear(); - - // Determine whether we are allowed to call explicit constructors or - // explicit conversion operators. - bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || - Kind.getKind() == InitializationKind::IK_Value || - Kind.getKind() == InitializationKind::IK_Default); - - // The type we're constructing needs to be complete. - if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { - Sequence.SetFailed(InitializationSequence::FK_Incomplete); - return; - } - - // The type we're converting to is a class type. Enumerate its constructors - // to see if one is suitable. - const RecordType *DestRecordType = DestType->getAs(); - assert(DestRecordType && "Constructor initialization requires record type"); - CXXRecordDecl *DestRecordDecl - = cast(DestRecordType->getDecl()); - - DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); - Con != ConEnd; ++Con) { - NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - bool SuppressUserConversions = false; - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl = dyn_cast(D); - if (ConstructorTmpl) - Constructor = cast( - ConstructorTmpl->getTemplatedDecl()); - else { - Constructor = cast(D); - - // If we're performing copy initialization using a copy constructor, we - // suppress user-defined conversions on the arguments. - // FIXME: Move constructors? - if (Kind.getKind() == InitializationKind::IK_Copy && - Constructor->isCopyConstructor()) - SuppressUserConversions = true; - } - - if (!Constructor->isInvalidDecl() && - (AllowExplicit || !Constructor->isExplicit())) { - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet, - SuppressUserConversions); - else - S.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet, - SuppressUserConversions); - } - } - - SourceLocation DeclLoc = Kind.getLocation(); - - // Perform overload resolution. If it fails, return the failed result. - OverloadCandidateSet::iterator Best; - if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { - Sequence.SetOverloadFailure( - InitializationSequence::FK_ConstructorOverloadFailed, - Result); - return; - } - - // C++0x [dcl.init]p6: - // If a program calls for the default initialization of an object - // of a const-qualified type T, T shall be a class type with a - // user-provided default constructor. - if (Kind.getKind() == InitializationKind::IK_Default && - Entity.getType().isConstQualified() && - cast(Best->Function)->isImplicit()) { - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); - return; - } - - // Add the constructor initialization step. Any cv-qualification conversion is - // subsumed by the initialization. - bool HadMultipleCandidates = (CandidateSet.size() > 1); - CXXConstructorDecl *CtorDecl = cast(Best->Function); - Sequence.AddConstructorInitializationStep(CtorDecl, - Best->FoundDecl.getAccess(), - DestType, HadMultipleCandidates); -} - /// \brief Attempt value initialization (C++ [dcl.init]p7). static void TryValueInitialization(Sema &S, const InitializedEntity &Entity, @@ -4526,6 +4592,117 @@ static bool isReferenceBinding(const InitializationSequence::Step &s) { s.Kind == InitializationSequence::SK_BindReferenceToTemporary; } +static ExprResult +PerformConstructorInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + const InitializationSequence::Step& Step, + bool &ConstructorInitRequiresZeroInit) { + unsigned NumArgs = Args.size(); + CXXConstructorDecl *Constructor + = cast(Step.Function.Function); + bool HadMultipleCandidates = Step.Function.HadMultipleCandidates; + + // Build a call to the selected constructor. + ASTOwningVector ConstructorArgs(S); + SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) + ? Kind.getEqualLoc() + : Kind.getLocation(); + + if (Kind.getKind() == InitializationKind::IK_Default) { + // Force even a trivial, implicit default constructor to be + // semantically checked. We do this explicitly because we don't build + // the definition for completely trivial constructors. + CXXRecordDecl *ClassDecl = Constructor->getParent(); + assert(ClassDecl && "No parent class for constructor."); + if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() && + ClassDecl->hasTrivialDefaultConstructor() && + !Constructor->isUsed(false)) + S.DefineImplicitDefaultConstructor(Loc, Constructor); + } + + ExprResult CurInit = S.Owned((Expr *)0); + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, move(Args), + Loc, ConstructorArgs)) + return ExprError(); + + + if (Entity.getKind() == InitializedEntity::EK_Temporary && + NumArgs != 1 && // FIXME: Hack to work around cast weirdness + (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value)) { + // An explicitly-constructed temporary, e.g., X(1, 2). + unsigned NumExprs = ConstructorArgs.size(); + Expr **Exprs = (Expr **)ConstructorArgs.take(); + S.MarkDeclarationReferenced(Loc, Constructor); + S.DiagnoseUseOfDecl(Constructor, Loc); + + TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); + if (!TSInfo) + TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); + + CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, + Constructor, + TSInfo, + Exprs, + NumExprs, + Kind.getParenRange(), + HadMultipleCandidates, + ConstructorInitRequiresZeroInit)); + } else { + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete; + + if (Entity.getKind() == InitializedEntity::EK_Base) { + ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? + CXXConstructExpr::CK_VirtualBase : + CXXConstructExpr::CK_NonVirtualBase; + } else if (Entity.getKind() == InitializedEntity::EK_Delegating) { + ConstructKind = CXXConstructExpr::CK_Delegating; + } + + // Only get the parenthesis range if it is a direct construction. + SourceRange parenRange = + Kind.getKind() == InitializationKind::IK_Direct ? + Kind.getParenRange() : SourceRange(); + + // If the entity allows NRVO, mark the construction as elidable + // unconditionally. + if (Entity.allowsNRVO()) + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, /*Elidable=*/true, + move_arg(ConstructorArgs), + HadMultipleCandidates, + ConstructorInitRequiresZeroInit, + ConstructKind, + parenRange); + else + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + HadMultipleCandidates, + ConstructorInitRequiresZeroInit, + ConstructKind, + parenRange); + } + if (CurInit.isInvalid()) + return ExprError(); + + // Only check access if all of that succeeded. + S.CheckConstructorAccess(Loc, Constructor, Entity, + Step.Function.FoundDecl.getAccess()); + S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc); + + if (shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); + + return move(CurInit); +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -4910,8 +5087,14 @@ InitializationSequence::Perform(Sema &S, break; } - case SK_ListConstructorCall: - assert(false && "List constructor calls not yet supported."); + case SK_ListConstructorCall: { + InitListExpr *InitList = cast(CurInit.get()); + MultiExprArg Arg(InitList->getInits(), InitList->getNumInits()); + CurInit = PerformConstructorInitialization(S, Entity, Kind, + move(Arg), *Step, + ConstructorInitRequiresZeroInit); + break; + } case SK_UnwrapInitList: CurInit = S.Owned(cast(CurInit.take())->getInit(0)); @@ -4929,108 +5112,11 @@ InitializationSequence::Perform(Sema &S, break; } - case SK_ConstructorInitialization: { - unsigned NumArgs = Args.size(); - CXXConstructorDecl *Constructor - = cast(Step->Function.Function); - bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; - - // Build a call to the selected constructor. - ASTOwningVector ConstructorArgs(S); - SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) - ? Kind.getEqualLoc() - : Kind.getLocation(); - - if (Kind.getKind() == InitializationKind::IK_Default) { - // Force even a trivial, implicit default constructor to be - // semantically checked. We do this explicitly because we don't build - // the definition for completely trivial constructors. - CXXRecordDecl *ClassDecl = Constructor->getParent(); - assert(ClassDecl && "No parent class for constructor."); - if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() && - ClassDecl->hasTrivialDefaultConstructor() && - !Constructor->isUsed(false)) - S.DefineImplicitDefaultConstructor(Loc, Constructor); - } - - // Determine the arguments required to actually perform the constructor - // call. - if (S.CompleteConstructorCall(Constructor, move(Args), - Loc, ConstructorArgs)) - return ExprError(); - - - if (Entity.getKind() == InitializedEntity::EK_Temporary && - NumArgs != 1 && // FIXME: Hack to work around cast weirdness - (Kind.getKind() == InitializationKind::IK_Direct || - Kind.getKind() == InitializationKind::IK_Value)) { - // An explicitly-constructed temporary, e.g., X(1, 2). - unsigned NumExprs = ConstructorArgs.size(); - Expr **Exprs = (Expr **)ConstructorArgs.take(); - S.MarkDeclarationReferenced(Loc, Constructor); - S.DiagnoseUseOfDecl(Constructor, Loc); - - TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); - if (!TSInfo) - TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); - - CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, - Constructor, - TSInfo, - Exprs, - NumExprs, - Kind.getParenRange(), - HadMultipleCandidates, - ConstructorInitRequiresZeroInit)); - } else { - CXXConstructExpr::ConstructionKind ConstructKind = - CXXConstructExpr::CK_Complete; - - if (Entity.getKind() == InitializedEntity::EK_Base) { - ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? - CXXConstructExpr::CK_VirtualBase : - CXXConstructExpr::CK_NonVirtualBase; - } else if (Entity.getKind() == InitializedEntity::EK_Delegating) { - ConstructKind = CXXConstructExpr::CK_Delegating; - } - - // Only get the parenthesis range if it is a direct construction. - SourceRange parenRange = - Kind.getKind() == InitializationKind::IK_Direct ? - Kind.getParenRange() : SourceRange(); - - // If the entity allows NRVO, mark the construction as elidable - // unconditionally. - if (Entity.allowsNRVO()) - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, /*Elidable=*/true, - move_arg(ConstructorArgs), - HadMultipleCandidates, - ConstructorInitRequiresZeroInit, - ConstructKind, - parenRange); - else - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, - move_arg(ConstructorArgs), - HadMultipleCandidates, - ConstructorInitRequiresZeroInit, - ConstructKind, - parenRange); - } - if (CurInit.isInvalid()) - return ExprError(); - - // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, Entity, - Step->Function.FoundDecl.getAccess()); - S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc); - - if (shouldBindAsTemporary(Entity)) - CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); - + case SK_ConstructorInitialization: + CurInit = PerformConstructorInitialization(S, Entity, Kind, move(Args), + *Step, + ConstructorInitRequiresZeroInit); break; - } case SK_ZeroInitialization: { step_iterator NextStep = Step; diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp index ac8794f455..03f25ba1de 100644 --- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp @@ -14,56 +14,56 @@ bool b; Aggr ag = { b }; // with no user-provided constructors, ... -struct NonAggr1a { - NonAggr1a(int, int); +struct NonAggr1a { // expected-note 2 {{candidate constructor}} + NonAggr1a(int, int); // expected-note {{candidate constructor}} int k; }; // In C++0x, 'user-provided' is only defined for special member functions, so // this type is considered to be an aggregate. This is considered to be // a language defect. -NonAggr1a na1a = { 42 }; // expected-error {{non-aggregate type 'NonAggr1a'}} +NonAggr1a na1a = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1a'}} struct NonAggr1b { - NonAggr1b(const NonAggr1b &); + NonAggr1b(const NonAggr1b &); // expected-note {{candidate constructor}} int k; }; -NonAggr1b na1b = { 42 }; // expected-error {{non-aggregate type 'NonAggr1b'}} +NonAggr1b na1b = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1b'}} // no brace-or-equal-initializers for non-static data members, ... -struct NonAggr2 { +struct NonAggr2 { // expected-note 3 {{candidate constructor}} int m = { 123 }; }; -NonAggr2 na2 = { 42 }; // expected-error {{non-aggregate type 'NonAggr2'}} +NonAggr2 na2 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr2'}} // no private... -struct NonAggr3 { +struct NonAggr3 { // expected-note 3 {{candidate constructor}} private: int n; }; -NonAggr3 na3 = { 42 }; // expected-error {{non-aggregate type 'NonAggr3'}} +NonAggr3 na3 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr3'}} // or protected non-static data members, ... -struct NonAggr4 { +struct NonAggr4 { // expected-note 3 {{candidate constructor}} protected: int n; }; -NonAggr4 na4 = { 42 }; // expected-error {{non-aggregate type 'NonAggr4'}} +NonAggr4 na4 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr4'}} // no base classes, ... -struct NonAggr5 : Aggr { +struct NonAggr5 : Aggr { // expected-note 3 {{candidate constructor}} }; -NonAggr5 na5 = { b }; // expected-error {{non-aggregate type 'NonAggr5'}} +NonAggr5 na5 = { b }; // expected-error {{no matching constructor for initialization of 'NonAggr5'}} template -struct MaybeAggr5a : BaseList... {}; +struct MaybeAggr5a : BaseList... {}; // expected-note {{explicitly marked deleted}} MaybeAggr5a<> ma5a0 = {}; // ok -MaybeAggr5a ma5a1 = {}; // expected-error {{non-aggregate type 'MaybeAggr5a'}} +MaybeAggr5a ma5a1 = {}; // expected-error {{call to deleted constructor of 'MaybeAggr5a'}} // and no virtual functions. -struct NonAggr6 { +struct NonAggr6 { // expected-note 3 {{candidate constructor}} virtual void f(); int n; }; -NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}} +NonAggr6 na6 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr6'}} struct DefaultedAggr { int n; diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp index 3c0e4483c4..885bf703dc 100644 --- a/test/SemaCXX/aggregate-initialization.cpp +++ b/test/SemaCXX/aggregate-initialization.cpp @@ -1,33 +1,33 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -// Verify that we can't initialize non-aggregates with an initializer -// list. +// Verify that using an initializer list for a non-aggregate looks for +// constructors.. // Note that due to a (likely) standard bug, this is technically an aggregate, // but we do not treat it as one. -struct NonAggr1 { - NonAggr1(int) { } +struct NonAggr1 { // expected-note 2 {{candidate constructor}} + NonAggr1(int, int) { } // expected-note {{candidate constructor}} int m; }; struct Base { }; -struct NonAggr2 : public Base { +struct NonAggr2 : public Base { // expected-note 3 {{candidate constructor}} int m; }; -class NonAggr3 { +class NonAggr3 { // expected-note 3 {{candidate constructor}} int m; }; -struct NonAggr4 { +struct NonAggr4 { // expected-note 3 {{candidate constructor}} int m; virtual void f(); }; -NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'NonAggr1' cannot be initialized with an initializer list}} -NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'NonAggr2' cannot be initialized with an initializer list}} -NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'NonAggr3' cannot be initialized with an initializer list}} -NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'NonAggr4' cannot be initialized with an initializer list}} +NonAggr1 na1 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr1'}} +NonAggr2 na2 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr2'}} +NonAggr3 na3 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr3'}} +NonAggr4 na4 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr4'}} // PR5817 typedef int type[][2]; diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp new file mode 100644 index 0000000000..7eff4c41aa --- /dev/null +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +namespace objects { + + struct X1 { X1(int); }; + struct X2 { explicit X2(int); }; // expected-note 2 {{candidate constructor}} + + template + struct A { + A() { static_assert(N == 0, ""); } + A(int, double) { static_assert(N == 1, ""); } + }; + + template + struct E { + E(int, int) { static_assert(N == 0, ""); } + E(X1, int) { static_assert(N == 1, ""); } + }; + + void overload_resolution() { + { A<0> a{}; } + { A<0> a = {}; } + { A<1> a{1, 1.0}; } + { A<1> a = {1, 1.0}; } + + { E<0> e{1, 2}; } + } + + void explicit_implicit() { + { X1 x{0}; } + { X1 x = {0}; } + { X2 x{0}; } + { X2 x = {0}; } // expected-error {{no matching constructor}} + } + + struct C { + C(); + C(int, double); + C(int, int); + + int operator[](C); + }; + + C function_call() { + void takes_C(C); + takes_C({1, 1.0}); + + //C c; + //c[{1, 1.0}]; needs overloading + + return {1, 1.0}; + } + + void inline_init() { + //(void) C{1, 1.0}; FIXME: inline initialization + (void) new C{1, 1.0}; + } + + struct B { + B(C, int, C); + }; + + void nested_init() { + //B b{{1, 1.0}, 2, {3, 4}}; needs overloading + } +} -- 2.40.0