diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-01-31 09:12:51 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-01-31 09:12:51 +0000 |
commit | 9db7dbb918ca49f4ee6c181e4917e7b6ec547353 (patch) | |
tree | ca2970a7b2115f226131005dc0c162108fc18720 | |
parent | a05315436746963c4034555ca725956507e14553 (diff) |
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94952 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 46 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 12 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 12 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 5 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 33 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 62 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 55 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 478 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 86 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 43 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.init/p6.cpp | 15 | ||||
-rw-r--r-- | test/SemaCXX/constructor-initializer.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/copy-assignment.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/illegal-member-initialization.cpp | 7 | ||||
-rw-r--r-- | test/SemaCXX/overload-member-call.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/overloaded-operator.cpp | 2 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-initializers.cpp | 2 |
22 files changed, 526 insertions, 403 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 30a4e96904..0fbdfe97cb 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -941,9 +941,9 @@ class CXXBaseOrMemberInitializer { /// \brief The source location for the field name. SourceLocation MemberLocation; - /// Args - The arguments used to initialize the base or member. - Stmt **Args; - unsigned NumArgs; + /// \brief The argument used to initialize the base or member, which may + /// end up constructing an object (when multiple arguments are involved). + Stmt *Init; /// \brief Stores either the constructor to call to initialize this base or /// member (a CXXConstructorDecl pointer), or stores the anonymous union of @@ -963,7 +963,7 @@ class CXXBaseOrMemberInitializer { /// @endcode /// In above example, BaseOrMember holds the field decl. for anonymous union /// and AnonUnionMember holds field decl for au_i1. - llvm::PointerUnion<CXXConstructorDecl *, FieldDecl *> CtorOrAnonUnion; + FieldDecl *AnonUnionMember; /// LParenLoc - Location of the left paren of the ctor-initializer. SourceLocation LParenLoc; @@ -975,30 +975,22 @@ public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, CXXConstructorDecl *C, + TypeSourceInfo *TInfo, SourceLocation L, - Expr **Args, unsigned NumArgs, + Expr *Init, SourceLocation R); /// CXXBaseOrMemberInitializer - Creates a new member initializer. explicit CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, - CXXConstructorDecl *C, SourceLocation L, - Expr **Args, unsigned NumArgs, + SourceLocation L, + Expr *Init, SourceLocation R); /// \brief Destroy the base or member initializer. void Destroy(ASTContext &Context); - /// arg_iterator - Iterates through the member initialization - /// arguments. - typedef ExprIterator arg_iterator; - - /// arg_const_iterator - Iterates through the member initialization - /// arguments. - typedef ConstExprIterator const_arg_iterator; - /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. bool isBaseInitializer() const { return BaseOrMember.is<TypeSourceInfo*>(); } @@ -1048,32 +1040,16 @@ public: SourceRange getSourceRange() const; FieldDecl *getAnonUnionMember() const { - return CtorOrAnonUnion.dyn_cast<FieldDecl *>(); + return AnonUnionMember; } void setAnonUnionMember(FieldDecl *anonMember) { - CtorOrAnonUnion = anonMember; - } - - const CXXConstructorDecl *getConstructor() const { - return CtorOrAnonUnion.dyn_cast<CXXConstructorDecl *>(); + AnonUnionMember = anonMember; } SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - /// arg_begin() - Retrieve an iterator to the first initializer argument. - arg_iterator arg_begin() { return Args; } - /// arg_begin() - Retrieve an iterator to the first initializer argument. - const_arg_iterator const_arg_begin() const { return Args; } - - /// arg_end() - Retrieve an iterator past the last initializer argument. - arg_iterator arg_end() { return Args + NumArgs; } - /// arg_end() - Retrieve an iterator past the last initializer argument. - const_arg_iterator const_arg_end() const { return Args + NumArgs; } - - /// getNumArgs - Determine the number of arguments used to - /// initialize the member or base. - unsigned getNumArgs() const { return NumArgs; } + Expr *getInit() { return static_cast<Expr *>(Init); } }; /// CXXConstructorDecl - Represents a C++ constructor within a diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 98933dbfdc..a2b9f40012 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -613,6 +613,7 @@ class CXXConstructExpr : public Expr { SourceLocation Loc; bool Elidable : 1; bool ZeroInitialization : 1; + bool BaseInitialization : 1; Stmt **Args; unsigned NumArgs; @@ -621,7 +622,8 @@ protected: SourceLocation Loc, CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization = false); + bool ZeroInitialization = false, + bool BaseInitialization = false); ~CXXConstructExpr() { } virtual void DoDestroy(ASTContext &C); @@ -635,7 +637,8 @@ public: SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, - bool ZeroInitialization = false); + bool ZeroInitialization = false, + bool BaseInitialization = false); CXXConstructorDecl* getConstructor() const { return Constructor; } @@ -655,6 +658,11 @@ public: ZeroInitialization = ZeroInit; } + /// \brief Determines whether this constructor is actually constructing + /// a base class (rather than a complete object). + bool isBaseInitialization() const { return BaseInitialization; } + void setBaseInitialization(bool BI) { BaseInitialization = BI; } + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e15bf20f0c..423988f47b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -588,6 +588,8 @@ def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_const_var_requires_init : Error< "declaration of const variable '%0' requires an initializer">; +def err_reference_without_init : Error< + "reference to type %0 requires an initializer">; def err_reference_has_multiple_inits : Error< "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< @@ -880,10 +882,7 @@ def err_uninitialized_member_for_assign : Error< "assignment operator">; def note_first_required_here : Note< "synthesized method is first required here">; -def err_null_intialized_reference_member : Error< - "cannot initialize the member to null in default constructor because " - "reference member %0 cannot be null-initialized">; -def err_unintialized_member_in_ctor : Error< +def err_uninitialized_member_in_ctor : Error< "%select{|implicit default }0constructor for %1 must explicitly initialize " "the %select{reference|const}2 member %3">; @@ -1949,7 +1948,8 @@ def err_new_paren_array_nonconst : Error< def err_array_size_not_integral : Error< "array size expression must have integral or enumerated type, not %0">; def err_default_init_const : Error< - "default initialization of an object of const type %0">; + "default initialization of an object of const type %0" + "%select{| requires a user-provided default constructor}1">; def err_delete_operand : Error<"cannot delete expression of type %0">; def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " "expression of type %0 to a pointer">; @@ -2252,8 +2252,6 @@ def error_multiple_base_initialization : Error < def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; -def err_mem_initializer_mismatch : Error< - "Too many arguments for member initializer %0">; def warn_field_initialized : Warning< "member '%0' will be initialized after">, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3d470e6244..6b398f62f6 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1654,9 +1654,12 @@ public: /// a well-formed program), ColonLoc is the location of the ':' that /// starts the constructor initializer, and MemInit/NumMemInits /// contains the individual member (and base) initializers. + /// AnyErrors will be true if there were any invalid member initializers + /// that are not represented in the list. virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits){ + MemInitTy **MemInits, unsigned NumMemInits, + bool AnyErrors){ } virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {} diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 73f47d9bc0..3d690d15f2 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -673,42 +673,25 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, CXXConstructorDecl *C, - SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + TypeSourceInfo *TInfo, + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, - CXXConstructorDecl *C, SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), - CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), + AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Destroy(Context); - Context.Deallocate(Args); + if (Init) + Init->Destroy(Context); this->~CXXBaseOrMemberInitializer(); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 32ac53d85b..a625865ecd 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -403,32 +404,51 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { CXXBaseOrMemberInitializer * BMInitializer = (*B); if (B != CDecl->init_begin()) Out << ", "; - bool hasArguments = (BMInitializer->arg_begin() != - BMInitializer->arg_end()); if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); Out << FD->getNameAsString(); + } else { + Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } - else // FIXME. skip dependent types for now. - if (const RecordType *RT = - BMInitializer->getBaseClass()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(RT->getDecl()); - Out << BaseDecl->getNameAsString(); - } - if (hasArguments) { - Out << "("; - for (CXXBaseOrMemberInitializer::const_arg_iterator BE = - BMInitializer->const_arg_begin(), - EE = BMInitializer->const_arg_end(); BE != EE; ++BE) { - if (BE != BMInitializer->const_arg_begin()) - Out<< ", "; - const Expr *Exp = (*BE); - Exp->printPretty(Out, Context, 0, Policy, Indentation); + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (CXXExprWithTemporaries *Tmp + = dyn_cast<CXXExprWithTemporaries>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); + } } - Out << ")"; - } else - Out << "()"; + } + Out << ")"; } } } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3931bbd6da..70d0891023 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -424,22 +424,26 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, - bool ZeroInitialization) { + bool ZeroInitialization, + bool BaseInitialization) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, ZeroInitialization); + Elidable, Args, NumArgs, ZeroInitialization, + BaseInitialization); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization) + bool ZeroInitialization, + bool BaseInitialization) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), + BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 1b337ebc1d..c965b34298 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -811,11 +811,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8); V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo()); - - CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), - Ctor_Base, V, - BaseInit->const_arg_begin(), - BaseInit->const_arg_end()); + CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); } static void EmitMemberInitializer(CodeGenFunction &CGF, @@ -846,55 +842,34 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // We lose the constructor for anonymous union members, so handle them // explicitly. - // FIXME: This is somwhat ugly. + // FIXME: This is somwhat ugly, and doesn't seem necessary at all. if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) { - if (MemberInit->getNumArgs()) - CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(), + if (MemberInit->getInit()) + CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), LHS.isVolatileQualified()); else CGF.EmitAggregateClear(LHS.getAddress(), Field->getType()); return; } - if (FieldType->getAs<RecordType>()) { - assert(MemberInit->getConstructor() && - "EmitCtorPrologue - no constructor to initialize member"); - if (Array) { - const llvm::Type *BasePtr = CGF.ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); - CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), - Array, BaseAddrPtr, - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - } - else - CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), - Ctor_Complete, LHS.getAddress(), - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - return; - } - - assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only"); - Expr *RhsExpr = *MemberInit->arg_begin(); + // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer + // was implicitly generated, we shouldn't be zeroing memory. RValue RHS; if (FieldType->isReferenceType()) { - RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType, - /*IsInitializer=*/true); + RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(), FieldType, + /*IsInitializer=*/true); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (Array) { + } else if (Array && !MemberInit->getInit()) { CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); - } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) { - RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true)); + } else if (!CGF.hasAggregateLLVMType(Field->getType())) { + RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true)); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (RhsExpr->getType()->isAnyComplexType()) { - CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(), + } else if (MemberInit->getInit()->getType()->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(), LHS.isVolatileQualified()); } else { - // Handle member function pointers; other aggregates shouldn't get this far. - CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified()); + CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), + LHS.isVolatileQualified(), false, true); } } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 2e8aea5e43..d7e6dbfa36 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -339,7 +339,9 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, } else // Call the constructor. - EmitCXXConstructorCall(CD, Ctor_Complete, Dest, + EmitCXXConstructorCall(CD, + E->isBaseInitialization()? Ctor_Base : Ctor_Complete, + Dest, E->arg_begin(), E->arg_end()); } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 04845d3b41..87bb3cb2b1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1550,12 +1550,15 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { SourceLocation ColonLoc = ConsumeToken(); llvm::SmallVector<MemInitTy*, 4> MemInitializers; - + bool AnyErrors = false; + do { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) MemInitializers.push_back(MemInit.get()); - + else + AnyErrors = true; + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) @@ -1569,7 +1572,8 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { } while (true); Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, - MemInitializers.data(), MemInitializers.size()); + MemInitializers.data(), MemInitializers.size(), + AnyErrors); } /// ParseMemInitializer - Parse a C++ member initializer, which is diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 86dbff3037..6f1ab14778 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1911,7 +1911,8 @@ public: QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg Exprs, - bool RequiresZeroInit = false); + bool RequiresZeroInit = false, + bool BaseInitialization = false); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? @@ -1920,7 +1921,8 @@ public: CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, - bool RequiresZeroInit = false); + bool RequiresZeroInit = false, + bool BaseInitialization = false); OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons, QualType writtenTy, @@ -2282,9 +2284,10 @@ public: CXXRecordDecl *ClassDecl); bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, - bool IsImplicitConstructor); + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + bool IsImplicitConstructor, + bool AnyErrors); /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl, /// mark all its non-trivial member and base destructor declarations @@ -2316,7 +2319,8 @@ public: virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits); + MemInitTy **MemInits, unsigned NumMemInits, + bool AnyErrors); void CheckCompletedCXXClass(CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 130bf4dbdf..f23f702d05 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1195,10 +1195,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); - // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) // where foo is not also a parameter to the constructor. @@ -1220,65 +1216,80 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); - CXXConstructorDecl *C = 0; QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - if (FieldType->isDependentType()) { - // Can't check init for dependent type. - } else if (FieldType->isRecordType()) { - // Member is a record (struct/union/class), so pass the initializer - // arguments down to the record's constructor. - if (!HasDependentArg) { - C = PerformInitializationByConstructor(FieldType, - MultiExprArg(*this, - (void**)Args, - NumArgs), - IdLoc, - SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), - InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), - ConstructorArgs); - - if (C) { - // Take over the constructor arguments as our own. - NumArgs = ConstructorArgs.size(); - Args = (Expr **)ConstructorArgs.take(); - } - } - } else if (NumArgs != 1 && NumArgs != 0) { - // The member type is not a record type (or an array of record - // types), so it can be only be default- or copy-initialized. - return Diag(IdLoc, diag::err_mem_initializer_mismatch) - << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); - } else if (!HasDependentArg) { - Expr *NewExp; - if (NumArgs == 0) { - if (FieldType->isReferenceType()) { - Diag(IdLoc, diag::err_null_intialized_reference_member) - << Member->getDeclName(); - return Diag(Member->getLocation(), diag::note_declared_at); - } - NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc); - NumArgs = 1; - } - else - NewExp = (Expr*)Args[0]; - if (!Member->isInvalidDecl() && - PerformCopyInitialization(NewExp, FieldType, AA_Passing)) - return true; - Args[0] = NewExp; + if (FieldType->isDependentType() || HasDependentArg) { + // Can't check initialization for a member of dependent type or when + // any of the arguments are type-dependent expressions. + OwningExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc)); + + // Erase any temporaries within this evaluation context; we're not + // going to track them in the AST, since we'll be rebuilding the + // ASTs during template instantiation. + ExprTemporaries.erase( + ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, + ExprTemporaries.end()); + + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + LParenLoc, + Init.takeAs<Expr>(), + RParenLoc); + } - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); + if (Member->isInvalidDecl()) + return true; + + // Initialize the member. + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(Member, 0); + InitializationKind Kind = + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - // FIXME: Perform direct initialization of the member. + OwningExprResult MemberInit = + InitSeq.Perform(*this, MemberEntity, Kind, + MultiExprArg(*this, (void**)Args, NumArgs), 0); + if (MemberInit.isInvalid()) + return true; + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // |