From 5b9cc5df25c2198f270dd1d5c438fdce70d4051d Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sat, 11 Feb 2012 23:51:47 +0000 Subject: [PATCH] Represent C++ direct initializers as ParenListExprs before semantic analysis instead of having a special-purpose function. - ActOnCXXDirectInitializer, which was mostly duplication of AddInitializerToDecl (leading e.g. to PR10620, which Eli fixed a few days ago), is dropped completely. - MultiInitializer, which was an ugly hack I added, is dropped again. - We now have the infrastructure in place to distinguish between int x = {1}; int x({1}); int x{1}; -- VarDecl now has getInitStyle(), which indicates which of the above was used. -- CXXConstructExpr now has a flag to indicate that it represents list- initialization, although this is not yet used. - InstantiateInitializer was renamed to SubstInitializer and simplified. - ActOnParenOrParenListExpr has been replaced by ActOnParenListExpr, which always produces a ParenListExpr. Placed that so far failed to convert that back to a ParenExpr containing comma operators have been fixed. I'm pretty sure I could have made a crashing test case before this. The end result is a (I hope) considerably cleaner design of initializers. More importantly, the fact that I can now distinguish between the various initialization kinds means that I can get the tricky generalized initializer test cases Johannes Schaub supplied to work. (This is not yet done.) This commit passed self-host, with the resulting compiler passing the tests. I hope it doesn't break more complicated code. It's a pretty big change, but one that I feel is necessary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150318 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 40 +- include/clang/AST/Expr.h | 2 +- include/clang/AST/ExprCXX.h | 33 +- include/clang/Sema/Initialization.h | 24 +- include/clang/Sema/MultiInitializer.h | 72 ---- include/clang/Sema/Sema.h | 33 +- lib/AST/DeclPrinter.cpp | 22 +- lib/AST/DumpXML.cpp | 8 +- lib/AST/Expr.cpp | 5 +- lib/AST/ExprCXX.cpp | 10 +- lib/CodeGen/CGObjC.cpp | 3 +- lib/Parse/ParseDecl.cpp | 9 +- lib/Parse/ParseExpr.cpp | 4 +- lib/Sema/CMakeLists.txt | 1 - lib/Sema/MultiInitializer.cpp | 93 ----- lib/Sema/SemaDecl.cpp | 122 +++++-- lib/Sema/SemaDeclCXX.cpp | 345 +++++------------- lib/Sema/SemaExpr.cpp | 22 +- lib/Sema/SemaInit.cpp | 7 + lib/Sema/SemaTemplateInstantiate.cpp | 14 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 170 +++------ lib/Sema/TreeTransform.h | 7 +- lib/Serialization/ASTReaderDecl.cpp | 2 +- lib/Serialization/ASTWriterDecl.cpp | 6 +- test/CXX/temp/temp.decls/temp.variadic/p5.cpp | 2 +- test/Sema/paren-list-expr-type.cpp | 17 - test/SemaTemplate/nested-incomplete-class.cpp | 21 ++ 27 files changed, 409 insertions(+), 685 deletions(-) delete mode 100644 include/clang/Sema/MultiInitializer.h delete mode 100644 lib/Sema/MultiInitializer.cpp delete mode 100644 test/Sema/paren-list-expr-type.cpp create mode 100644 test/SemaTemplate/nested-incomplete-class.cpp diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 24d2d85385..f04ad9f356 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -681,6 +681,13 @@ public: /// It is illegal to call this function with SC == None. static const char *getStorageClassSpecifierString(StorageClass SC); + /// \brief Initialization styles. + enum InitializationStyle { + CInit, ///< C-style initialization with assignment + CallInit, ///< Call-style initialization (C++98) + ListInit ///< Direct list-initialization (C++11) + }; + protected: /// \brief Placeholder type used in Init to denote an unparsed C++ default /// argument. @@ -706,7 +713,7 @@ private: unsigned SClass : 3; unsigned SClassAsWritten : 3; unsigned ThreadSpecified : 1; - unsigned HasCXXDirectInit : 1; + unsigned InitStyle : 2; /// \brief Whether this variable is the exception variable in a C++ catch /// or an Objective-C @catch statement. @@ -728,7 +735,7 @@ private: /// \brief Whether this variable is (C++0x) constexpr. unsigned IsConstexpr : 1; }; - enum { NumVarDeclBits = 13 }; + enum { NumVarDeclBits = 14 }; friend class ASTDeclReader; friend class StmtIteratorBase; @@ -756,7 +763,7 @@ protected: /// Otherwise, the number of function parameter scopes enclosing /// the function parameter scope in which this parameter was /// declared. - unsigned ScopeDepthOrObjCQuals : 8; + unsigned ScopeDepthOrObjCQuals : 7; /// The number of parameters preceding this parameter in the /// function parameter scope in which it was declared. @@ -1073,16 +1080,27 @@ public: /// declaration is an integral constant expression. bool checkInitIsICE() const; - void setCXXDirectInitializer(bool T) { VarDeclBits.HasCXXDirectInit = T; } + void setInitStyle(InitializationStyle Style) { + VarDeclBits.InitStyle = Style; + } - /// hasCXXDirectInitializer - If true, the initializer was a direct - /// initializer, e.g: "int x(1);". The Init expression will be the expression - /// inside the parens or a "ClassType(a,b,c)" class constructor expression for - /// class types. Clients can distinguish between "int x(1);" and "int x=1;" - /// by checking hasCXXDirectInitializer. + /// \brief The style of initialization for this declaration. /// - bool hasCXXDirectInitializer() const { - return VarDeclBits.HasCXXDirectInit; + /// C-style initialization is "int x = 1;". Call-style initialization is + /// a C++98 direct-initializer, e.g. "int x(1);". The Init expression will be + /// the expression inside the parens or a "ClassType(a,b,c)" class constructor + /// expression for class types. List-style initialization is C++11 syntax, + /// e.g. "int x{1};". Clients can distinguish between different forms of + /// initialization by checking this value. In particular, "int x = {1};" is + /// C-style, "int x({1})" is call-style, and "int x{1};" is list-style; the + /// Init expression in all three cases is an InitListExpr. + InitializationStyle getInitStyle() const { + return static_cast(VarDeclBits.InitStyle); + } + + /// \brief Whether the initializer is a direct-initializer (list or call). + bool isDirectInit() const { + return getInitStyle() != CInit; } /// \brief Determine whether this variable is the exception variable in a diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index f78138c16d..adf12c1b2d 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3977,7 +3977,7 @@ class ParenListExpr : public Expr { public: ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, - unsigned numexprs, SourceLocation rparenloc, QualType T); + unsigned numexprs, SourceLocation rparenloc); /// \brief Build an empty paren list. explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 395dcda72f..14918fa1d3 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -812,6 +812,7 @@ private: unsigned NumArgs : 16; bool Elidable : 1; bool HadMultipleCandidates : 1; + bool ListInitialization : 1; bool ZeroInitialization : 1; unsigned ConstructKind : 2; Stmt **Args; @@ -822,32 +823,36 @@ protected: CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs, bool HadMultipleCandidates, - bool ZeroInitialization = false, - ConstructionKind ConstructKind = CK_Complete, - SourceRange ParenRange = SourceRange()); + bool ListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange); /// \brief Construct an empty C++ construction expression. CXXConstructExpr(StmtClass SC, EmptyShell Empty) - : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(0), - HadMultipleCandidates(false), ZeroInitialization(0), - ConstructKind(0), Args(0) { } + : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(false), + HadMultipleCandidates(false), ListInitialization(false), + ZeroInitialization(false), ConstructKind(0), Args(0) + { } public: /// \brief Construct an empty C++ construction expression. explicit CXXConstructExpr(EmptyShell Empty) : Expr(CXXConstructExprClass, Empty), Constructor(0), - NumArgs(0), Elidable(0), HadMultipleCandidates(false), - ZeroInitialization(0), ConstructKind(0), Args(0) { } + NumArgs(0), Elidable(false), HadMultipleCandidates(false), + ListInitialization(false), ZeroInitialization(false), + ConstructKind(0), Args(0) + { } static CXXConstructExpr *Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool HadMultipleCandidates, - bool ZeroInitialization = false, - ConstructionKind ConstructKind = CK_Complete, - SourceRange ParenRange = SourceRange()); - + bool ListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange); CXXConstructorDecl* getConstructor() const { return Constructor; } void setConstructor(CXXConstructorDecl *C) { Constructor = C; } @@ -864,6 +869,10 @@ public: bool hadMultipleCandidates() const { return HadMultipleCandidates; } void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; } + /// \brief Whether this constructor call was written as list-initialization. + bool isListInitialization() const { return ListInitialization; } + void setListInitialization(bool V) { ListInitialization = V; } + /// \brief Whether this construction first requires /// zero-initialization before the initializer is called. bool requiresZeroInitialization() const { return ZeroInitialization; } diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 5fc6373acd..853f8897f2 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -326,20 +326,22 @@ class InitializationKind { public: /// \brief The kind of initialization being performed. enum InitKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default, ///< Default initialization - IK_Value ///< Value initialization + IK_Direct, ///< Direct initialization + IK_DirectList, ///< Direct list-initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization }; private: /// \brief The kind of initialization that we're storing. enum StoredInitKind { - SIK_Direct = IK_Direct, ///< Direct initialization - SIK_Copy = IK_Copy, ///< Copy initialization - SIK_Default = IK_Default, ///< Default initialization - SIK_Value = IK_Value, ///< Value initialization - SIK_ImplicitValue, ///< Implicit value initialization + SIK_Direct = IK_Direct, ///< Direct initialization + SIK_DirectList = IK_DirectList, ///< Direct list-initialization + SIK_Copy = IK_Copy, ///< Copy initialization + SIK_Default = IK_Default, ///< Default initialization + SIK_Value = IK_Value, ///< Value initialization + SIK_ImplicitValue, ///< Implicit value initialization SIK_DirectCast, ///< Direct initialization due to a cast /// \brief Direct initialization due to a C-style cast. SIK_DirectCStyleCast, @@ -370,6 +372,10 @@ public: return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); } + static InitializationKind CreateDirectList(SourceLocation InitLoc) { + return InitializationKind(SIK_DirectList, InitLoc, InitLoc, InitLoc); + } + /// \brief Create a direct initialization due to a cast that isn't a C-style /// or functional cast. static InitializationKind CreateCast(SourceRange TypeRange) { diff --git a/include/clang/Sema/MultiInitializer.h b/include/clang/Sema/MultiInitializer.h deleted file mode 100644 index c44e3934db..0000000000 --- a/include/clang/Sema/MultiInitializer.h +++ /dev/null @@ -1,72 +0,0 @@ -//===--- MultiInitializer.h - Initializer expression group ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the MultiInitializer class, which can represent a list -// initializer or a parentheses-wrapped group of expressions in a C++ member -// initializer. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_MULTIINITIALIZER_H -#define LLVM_CLANG_SEMA_MULTIINITIALIZER_H - -#include "clang/Sema/Ownership.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/PointerUnion.h" - -namespace clang { - class ASTContext; - class Expr; - class InitializationKind; - class InitializedEntity; - class InitListExpr; - class Sema; - -class MultiInitializer { - llvm::PointerUnion InitListOrExpressions; - unsigned NumInitializers; - SourceLocation LParenLoc; - SourceLocation RParenLoc; - - InitListExpr *getInitList() const; - Expr **getExpressions() const { return InitListOrExpressions.get(); } - -public: - MultiInitializer(Expr* InitList) - : InitListOrExpressions(InitList) - {} - - MultiInitializer(SourceLocation LParenLoc, Expr **Exprs, unsigned NumInits, - SourceLocation RParenLoc) - : InitListOrExpressions(Exprs), NumInitializers(NumInits), - LParenLoc(LParenLoc), RParenLoc(RParenLoc) - {} - - bool isInitializerList() const { return InitListOrExpressions.is(); } - - SourceLocation getStartLoc() const; - SourceLocation getEndLoc() const; - - typedef Expr **iterator; - iterator begin() const; - iterator end() const; - - bool isTypeDependent() const; - - bool DiagnoseUnexpandedParameterPack(Sema &SemaRef) const; - - // Return the InitListExpr or create a ParenListExpr. - Expr *CreateInitExpr(ASTContext &Ctx, QualType T) const; - - ExprResult PerformInit(Sema &SemaRef, InitializedEntity Entity, - InitializationKind Kind) const; -}; -} - -#endif diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b111e7bbe8..ce36d23706 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -22,7 +22,6 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/LocInfoType.h" -#include "clang/Sema/MultiInitializer.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "clang/AST/Expr.h" @@ -2387,9 +2386,9 @@ public: ExprResult ActOnNumericConstant(const Token &Tok); ExprResult ActOnCharacterConstant(const Token &Tok); ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); - ExprResult ActOnParenOrParenListExpr(SourceLocation L, - SourceLocation R, - MultiExprArg Val); + ExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). @@ -2769,15 +2768,6 @@ public: UnqualifiedId &Name, TypeResult Type); - /// AddCXXDirectInitializerToDecl - This action is called immediately after - /// ActOnDeclarator, when a C++ direct initializer is present. - /// e.g: "int x(1);" - void AddCXXDirectInitializerToDecl(Decl *Dcl, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation RParenLoc, - bool TypeMayContainAuto); - /// InitializeVarWithConstructor - Creates an CXXConstructExpr /// and sets it as the initializer for the the passed in VarDecl. bool InitializeVarWithConstructor(VarDecl *VD, @@ -3574,21 +3564,21 @@ public: ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, - const MultiInitializer &Init, + Expr *Init, SourceLocation EllipsisLoc); MemInitResult BuildMemberInitializer(ValueDecl *Member, - const MultiInitializer &Args, + Expr *Init, SourceLocation IdLoc); MemInitResult BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, - const MultiInitializer &Args, + Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc); MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, - const MultiInitializer &Args, + Expr *Init, CXXRecordDecl *ClassDecl); bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, @@ -5186,6 +5176,10 @@ public: Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); + ExprResult SubstInitializer(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool CXXDirectInit); + bool SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, @@ -5259,11 +5253,6 @@ public: void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); - bool InstantiateInitializer(Expr *Init, - const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation &LParenLoc, - ASTOwningVector &NewArgs, - SourceLocation &RParenLoc); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs); diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 5a6686d164..32bdba1a0b 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -621,16 +621,20 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { Out << Name; Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { - if (D->hasCXXDirectInitializer()) - Out << "("; - else { - CXXConstructExpr *CCE = dyn_cast(Init); - if (!CCE || CCE->getConstructor()->isCopyOrMoveConstructor()) - Out << " = "; + bool ImplicitInit = false; + if (CXXConstructExpr *Construct = dyn_cast(Init)) + ImplicitInit = D->getInitStyle() == VarDecl::CallInit && + Construct->getNumArgs() == 0 && !Construct->isListInitialization(); + if (!ImplicitInit) { + if (D->getInitStyle() == VarDecl::CallInit) + Out << "("; + else if (D->getInitStyle() == VarDecl::CInit) { + Out << " = "; + } + Init->printPretty(Out, Context, 0, Policy, Indentation); + if (D->getInitStyle() == VarDecl::CallInit) + Out << ")"; } - Init->printPretty(Out, Context, 0, Policy, Indentation); - if (D->hasCXXDirectInitializer()) - Out << ")"; } prettyPrintAttributes(D); } diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index dcbc5180a0..b4038ddaf9 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -461,7 +461,13 @@ struct XMLDumper : public XMLDeclVisitor, if (D->getStorageClass() != SC_None) set("storage", VarDecl::getStorageClassSpecifierString(D->getStorageClass())); - setFlag("directinit", D->hasCXXDirectInitializer()); + StringRef initStyle = ""; + switch (D->getInitStyle()) { + case VarDecl::CInit: initStyle = "c"; break; + case VarDecl::CallInit: initStyle = "call"; break; + case VarDecl::ListInit: initStyle = "list"; break; + } + set("initstyle", initStyle); setFlag("nrvo", D->isNRVOVariable()); // TODO: instantiation, etc. } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 398e27ea97..5d22d144f4 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -3414,11 +3414,10 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, unsigned nexprs, - SourceLocation rparenloc, QualType T) - : Expr(ParenListExprClass, T, VK_RValue, OK_Ordinary, + SourceLocation rparenloc) + : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { - assert(!T.isNull() && "ParenListExpr must have a valid type"); Exprs = new (C) Stmt*[nexprs]; for (unsigned i = 0; i != nexprs; ++i) { if (exprs[i]->isTypeDependent()) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 51dd57cfe3..a38488b877 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -653,7 +653,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, Type->getType().getNonReferenceType(), Type->getTypeLoc().getBeginLoc(), Cons, false, Args, NumArgs, - HadMultipleCandidates, ZeroInitialization, + HadMultipleCandidates, /*FIXME*/false, ZeroInitialization, CXXConstructExpr::CK_Complete, parenRange), Type(Type) { } @@ -668,13 +668,15 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool HadMultipleCandidates, + bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, NumArgs, - HadMultipleCandidates, ZeroInitialization, - ConstructKind, ParenRange); + HadMultipleCandidates, ListInitialization, + ZeroInitialization, ConstructKind, + ParenRange); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, @@ -682,6 +684,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, bool HadMultipleCandidates, + bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) @@ -691,6 +694,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, T->containsUnexpandedParameterPack()), Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), + ListInitialization(ListInitialization), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), Args(0) { diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index dc68605555..94bad92180 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -2740,7 +2740,8 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( CXXConstExpr->getConstructor(), CXXConstExpr->isElidable(), &ConstructorArgs[0], ConstructorArgs.size(), - CXXConstExpr->hadMultipleCandidates(), + CXXConstExpr->hadMultipleCandidates(), + CXXConstExpr->isListInitialization(), CXXConstExpr->requiresZeroInitialization(), CXXConstExpr->getConstructionKind(), SourceRange()); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 0c8a647f65..914a5acd09 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1344,10 +1344,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExitScope(); } - Actions.AddCXXDirectInitializerToDecl(ThisDecl, T.getOpenLocation(), - move_arg(Exprs), - T.getCloseLocation(), - TypeContainsAuto); + ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), + T.getCloseLocation(), + move_arg(Exprs)); + Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), + /*DirectInit=*/true, TypeContainsAuto); } } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { // Parse C++0x braced-init-list. diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 3660b01816..b5e4a5f620 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2006,8 +2006,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; - Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), - move_arg(ArgExprs)); + Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs)); } } else { InMessageExpressionRAIIObject InMessage(*this, false); diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index dece5bd998..c576d765b2 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -8,7 +8,6 @@ add_clang_library(clangSema DelayedDiagnostic.cpp IdentifierResolver.cpp JumpDiagnostics.cpp - MultiInitializer.cpp Scope.cpp Sema.cpp SemaAccess.cpp diff --git a/lib/Sema/MultiInitializer.cpp b/lib/Sema/MultiInitializer.cpp deleted file mode 100644 index d8944efba3..0000000000 --- a/lib/Sema/MultiInitializer.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===--- MultiInitializer.cpp - Initializer expression group ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the MultiInitializer class, which can represent a list -// initializer or a parentheses-wrapped group of expressions in a C++ member -// initializer. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/MultiInitializer.h" -#include "clang/Sema/Initialization.h" -#include "clang/Sema/Sema.h" -#include "clang/AST/Expr.h" - -using namespace clang; - -InitListExpr *MultiInitializer::getInitList() const { - return cast(InitListOrExpressions.get()); -} - -SourceLocation MultiInitializer::getStartLoc() const { - return isInitializerList() ? getInitList()->getLBraceLoc() : LParenLoc; -} - -SourceLocation MultiInitializer::getEndLoc() const { - return isInitializerList() ? getInitList()->getRBraceLoc() : RParenLoc; -} - -MultiInitializer::iterator MultiInitializer::begin() const { - return isInitializerList() ? getInitList()->getInits() : getExpressions(); -} - -MultiInitializer::iterator MultiInitializer::end() const { - if (isInitializerList()) { - InitListExpr *ILE = getInitList(); - return ILE->getInits() + ILE->getNumInits(); - } - return getExpressions() + NumInitializers; -} - -bool MultiInitializer::isTypeDependent() const { - if (isInitializerList()) - return getInitList()->isTypeDependent(); - for (iterator I = begin(), E = end(); I != E; ++I) { - if ((*I)->isTypeDependent()) - return true; - } - return false; -} - -bool MultiInitializer::DiagnoseUnexpandedParameterPack(Sema &SemaRef) const { - if (isInitializerList()) - return SemaRef.DiagnoseUnexpandedParameterPack(getInitList(), - Sema::UPPC_Initializer); - for (iterator I = begin(), E = end(); I != E; ++I) { - if (SemaRef.DiagnoseUnexpandedParameterPack(*I, Sema::UPPC_Initializer)) - return true; - } - return false; -} - -Expr *MultiInitializer::CreateInitExpr(ASTContext &Ctx, QualType T) const { - if (isInitializerList()) - return InitListOrExpressions.get(); - - return new (Ctx) ParenListExpr(Ctx, LParenLoc, getExpressions(), - NumInitializers, RParenLoc, T); -} - -ExprResult MultiInitializer::PerformInit(Sema &SemaRef, - InitializedEntity Entity, - InitializationKind Kind) const { - Expr *Single; - Expr **Args; - unsigned NumArgs; - if (isInitializerList()) { - Single = InitListOrExpressions.get(); - Args = &Single; - NumArgs = 1; - } else { - Args = getExpressions(); - NumArgs = NumInitializers; - } - InitializationSequence InitSeq(SemaRef, Entity, Kind, Args, NumArgs); - return InitSeq.Perform(SemaRef, Entity, Kind, - MultiExprArg(SemaRef, Args, NumArgs), 0); -} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6ba3228b08..feffaf13fa 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2139,9 +2139,8 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, /// emitting diagnostics as appropriate. /// /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back -/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't -/// check them before the initializer is attached. -/// +/// to here in AddInitializerToDecl. We can't check them before the initializer +/// is attached. void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { if (New->isInvalidDecl() || Old->isInvalidDecl()) return; @@ -5983,17 +5982,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (RealDecl == 0 || RealDecl->isInvalidDecl()) return; - // Check for self-references within variable initializers. - if (VarDecl *vd = dyn_cast(RealDecl)) { - // Variables declared within a function/method body are handled - // by a dataflow analysis. - if (!vd->hasLocalStorage() && !vd->isStaticLocal()) - CheckSelfReference(RealDecl, Init); - } - else { - CheckSelfReference(RealDecl, Init); - } - if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { // With declarators parsed the way they are, the parser cannot // distinguish between a normal initializer and a pure-specifier. @@ -6018,12 +6006,44 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, return; } + // Check for self-references within variable initializers. + // Variables declared within a function/method body are handled + // by a dataflow analysis. + if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal()) + CheckSelfReference(RealDecl, Init); + + ParenListExpr *CXXDirectInit = dyn_cast(Init); + // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { + Expr *DeduceInit = Init; + // Initializer could be a C++ direct-initializer. Deduction only works if it + // contains exactly one expression. + if (CXXDirectInit) { + if (CXXDirectInit->getNumExprs() == 0) { + // It isn't possible to write this directly, but it is possible to + // end up in this situation with "auto x(some_pack...);" + Diag(CXXDirectInit->getSourceRange().getBegin(), + diag::err_auto_var_init_no_expression) + << VDecl->getDeclName() << VDecl->getType() + << VDecl->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } else if (CXXDirectInit->getNumExprs() > 1) { + Diag(CXXDirectInit->getExpr(1)->getSourceRange().getBegin(), + diag::err_auto_var_init_multiple_expressions) + << VDecl->getDeclName() << VDecl->getType() + << VDecl->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } else { + DeduceInit = CXXDirectInit->getExpr(0); + } + } TypeSourceInfo *DeducedType = 0; - if (DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType) == + if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == DAR_Failed) - DiagnoseAutoDeductionFailure(VDecl, Init); + DiagnoseAutoDeductionFailure(VDecl, DeduceInit); if (!DeducedType) { RealDecl->setInvalidDecl(); return; @@ -6048,25 +6068,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, return; } + if (!VDecl->getType()->isDependentType()) { + // A definition must end up with a complete type, which means it must be + // complete with the restriction that an array type might be completed by + // the initializer; note that later code assumes this restriction. + QualType BaseDeclType = VDecl->getType(); + if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) + BaseDeclType = Array->getElementType(); + if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, + diag::err_typecheck_decl_incomplete_type)) { + RealDecl->setInvalidDecl(); + return; + } - // A definition must end up with a complete type, which means it must be - // complete with the restriction that an array type might be completed by the - // initializer; note that later code assumes this restriction. - QualType BaseDeclType = VDecl->getType(); - if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) - BaseDeclType = Array->getElementType(); - if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, - diag::err_typecheck_decl_incomplete_type)) { - RealDecl->setInvalidDecl(); - return; + // The variable can not have an abstract class type. + if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), + diag::err_abstract_type_in_decl, + AbstractVariableType)) + VDecl->setInvalidDecl(); } - // The variable can not have an abstract class type. - if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), - diag::err_abstract_type_in_decl, - AbstractVariableType)) - VDecl->setInvalidDecl(); - const VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl) { Diag(VDecl->getLocation(), diag::err_redefinition) @@ -6128,9 +6149,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); - InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + Expr **Args = &Init; + unsigned NumArgs = 1; + if (CXXDirectInit) { + Args = CXXDirectInit->getExprs(); + NumArgs = CXXDirectInit->getNumExprs(); + } + InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &Init, 1), + MultiExprArg(*this, Args,NumArgs), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); @@ -6266,6 +6293,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, CheckForConstantInitializer(Init, DclT); } + // We will represent direct-initialization similarly to copy-initialization: + // int x(1); -as-> int x = 1; + // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); + // + // Clients that want to distinguish between the two forms, can check for + // direct initializer using VarDecl::getInitStyle(). + // A major benefit is that clients that don't particularly care about which + // exactly form was it (like the CodeGen) can handle both cases without + // special case code. + + // C++ 8.5p11: + // The form of initialization (using parentheses or '=') is generally + // insignificant, but does matter when the entity being initialized has a + // class type. + if (CXXDirectInit) { + assert(DirectInit && "Call-style initializer must be direct init."); + VDecl->setInitStyle(VarDecl::CallInit); + } else if (DirectInit) { + // This must be list-initialization. No other way is direct-initialization. + VDecl->setInitStyle(VarDecl::ListInit); + } + CheckCompleteVariableDeclaration(VDecl); } @@ -6496,8 +6545,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, MultiExprArg(*this, 0, 0)); if (Init.isInvalid()) Var->setInvalidDecl(); - else if (Init.get()) + else if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); + // This is important for template substitution. + Var->setInitStyle(VarDecl::CallInit); + } CheckCompleteVariableDeclaration(Var); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a6d7d63b3a..72a8de2b71 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1768,7 +1768,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, Expr *InitList, SourceLocation EllipsisLoc) { return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, - DS, IdLoc, MultiInitializer(InitList), + DS, IdLoc, InitList, EllipsisLoc); } @@ -1785,10 +1785,10 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { + Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc); return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, - DS, IdLoc, MultiInitializer(LParenLoc, Args, - NumArgs, RParenLoc), - EllipsisLoc); + DS, IdLoc, List, EllipsisLoc); } namespace { @@ -1825,7 +1825,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, - const MultiInitializer &Args, + Expr *Init, SourceLocation EllipsisLoc) { if (!ConstructorD) return true; @@ -1864,9 +1864,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD, (Member = dyn_cast(*Result.first))) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); - return BuildMemberInitializer(Member, Args, IdLoc); + return BuildMemberInitializer(Member, Init, IdLoc); } } } @@ -1927,7 +1928,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, Diag(Member->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; - return BuildMemberInitializer(Member, Args, IdLoc); + return BuildMemberInitializer(Member, Init, IdLoc); } else if (TypeDecl *Type = Corr.getCorrectionDeclAs()) { const CXXBaseSpecifier *DirectBaseSpec; const CXXBaseSpecifier *VirtualBaseSpec; @@ -1955,7 +1956,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) - << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); + << MemberOrBase << SourceRange(IdLoc,Init->getSourceRange().getEnd()); return true; } } @@ -1975,7 +1976,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, TInfo, Args, ClassDecl, EllipsisLoc); + return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, EllipsisLoc); } /// Checks a member initializer expression for cases where reference (or @@ -2102,15 +2103,14 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, } MemInitResult -Sema::BuildMemberInitializer(ValueDecl *Member, - const MultiInitializer &Args, +Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { FieldDecl *DirectMember = dyn_cast(Member); IndirectFieldDecl *IndirectMember = dyn_cast(Member); assert((DirectMember || IndirectMember) && "Member must be a FieldDecl or IndirectFieldDecl"); - if (Args.DiagnoseUnexpandedParameterPack(*this)) + if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) return true; if (Member->isInvalidDecl()) @@ -2120,13 +2120,19 @@ Sema::BuildMemberInitializer(ValueDecl *Member, // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. - for (MultiInitializer::iterator I = Args.begin(), E = Args.end(); - I != E; ++I) { + Expr **Args; + unsigned NumArgs; + if (ParenListExpr *ParenList = dyn_cast(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else { + InitListExpr *InitList = cast(Init); + Args = InitList->getInits(); + NumArgs = InitList->getNumInits(); + } + for (unsigned i = 0; i < NumArgs; ++i) { SourceLocation L; - Expr *Arg = *I; - if (DesignatedInitExpr *DIE = dyn_cast(Arg)) - Arg = DIE->getInit(); - if (InitExprContainsUninitializedFields(Arg, Member, &L)) { + if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { // FIXME: Return true in the case when other fields are used before being // uninitialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th @@ -2137,14 +2143,11 @@ Sema::BuildMemberInitializer(ValueDecl *Member, } } - bool HasDependentArg = Args.isTypeDependent(); + SourceRange InitRange = Init->getSourceRange(); - Expr *Init; - if (Member->getType()->isDependentType() || HasDependentArg) { + if (Member->getType()->isDependentType() || Init->isTypeDependent()) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. - Init = Args.CreateInitExpr(Context,Member->getType().getNonReferenceType()); - DiscardCleanupsInEvaluationContext(); } else { // Initialize the member. @@ -2152,14 +2155,22 @@ Sema::BuildMemberInitializer(ValueDecl *Member, DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0) : InitializedEntity::InitializeMember(IndirectMember, 0); InitializationKind Kind = - InitializationKind::CreateDirect(IdLoc, Args.getStartLoc(), - Args.getEndLoc()); + InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), + InitRange.getEnd()); - ExprResult MemberInit = Args.PerformInit(*this, MemberEntity, Kind); + if (isa(Init)) { + Args = &Init; + NumArgs = 1; + } + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); + ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, + MultiExprArg(*this, Args, NumArgs), + 0); if (MemberInit.isInvalid()) return true; - CheckImplicitConversions(MemberInit.get(), Args.getStartLoc()); + CheckImplicitConversions(MemberInit.get(), + InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -2170,14 +2181,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, // If we are in a dependent context, template instantiation will // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. + // received. // FIXME: This isn't quite ideal, since our ASTs don't capture all // of the information that we have about the member // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) { - Init = Args.CreateInitExpr(Context, - Member->getType().getNonReferenceType()); + // The existing Init will do fine. } else { Init = MemberInit.get(); CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc); @@ -2185,19 +2195,18 @@ Sema::BuildMemberInitializer(ValueDecl *Member, } if (DirectMember) { - return new (Context) CXXCtorInitializer(Context, DirectMember, - IdLoc, Args.getStartLoc(), - Init, Args.getEndLoc()); + return new (Context) CXXCtorInitializer(Context, DirectMember, IdLoc, + InitRange.getBegin(), Init, + InitRange.getEnd()); } else { - return new (Context) CXXCtorInitializer(Context, IndirectMember, - IdLoc, Args.getStartLoc(), - Init, Args.getEndLoc()); + return new (Context) CXXCtorInitializer(Context, IndirectMember, IdLoc, + InitRange.getBegin(), Init, + InitRange.getEnd()); } } MemInitResult -Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, - const MultiInitializer &Args, +Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl) { SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) @@ -2205,21 +2214,31 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, << TInfo->getTypeLoc().getLocalSourceRange(); Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); + SourceRange InitRange = Init->getSourceRange(); // Initialize the object. InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = - InitializationKind::CreateDirect(NameLoc, Args.getStartLoc(), - Args.getEndLoc()); - - ExprResult DelegationInit = Args.PerformInit(*this, DelegationEntity, Kind); + InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), + InitRange.getEnd()); + + Expr **Args = &Init; + unsigned NumArgs = 1; + if (ParenListExpr *ParenList = dyn_cast(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } + InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); + ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, + MultiExprArg(*this, Args,NumArgs), + 0); if (DelegationInit.isInvalid()) return true; assert(cast(DelegationInit.get())->getConstructor() && "Delegating constructor with no target?"); - CheckImplicitConversions(DelegationInit.get(), Args.getStartLoc()); + CheckImplicitConversions(DelegationInit.get(), InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -2228,18 +2247,15 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, if (DelegationInit.isInvalid()) return true; - return new (Context) CXXCtorInitializer(Context, TInfo, Args.getStartLoc(), + return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.takeAs(), - Args.getEndLoc()); + InitRange.getEnd()); } MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, - const MultiInitializer &Args, - CXXRecordDecl *ClassDecl, + Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { - bool HasDependentArg = Args.isTypeDependent(); - SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); @@ -2253,13 +2269,14 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // of that class, the mem-initializer is ill-formed. A // mem-initializer-list can initialize a base class using any // name that denotes that base class type. - bool Dependent = BaseType->isDependentType() || HasDependentArg; + bool Dependent = BaseType->isDependentType() || Init->isTypeDependent(); + SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { // This is a pack expansion. if (!BaseType->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << SourceRange(BaseLoc, Args.getEndLoc()); + << SourceRange(BaseLoc, InitRange.getEnd()); EllipsisLoc = SourceLocation(); } @@ -2268,7 +2285,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer)) return true; - if (Args.DiagnoseUnexpandedParameterPack(*this)) + if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) return true; } @@ -2278,7 +2295,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) - return BuildDelegatingInitializer(BaseTInfo, Args, ClassDecl); + return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -2303,16 +2320,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, } if (Dependent) { - // Can't check initialization for a base of dependent type or when - // any of the arguments are type-dependent expressions. - Expr *BaseInit = Args.CreateInitExpr(Context, BaseType); - DiscardCleanupsInEvaluationContext(); return new (Context) CXXCtorInitializer(Context, BaseTInfo, /*IsVirtual=*/false, - Args.getStartLoc(), BaseInit, - Args.getEndLoc(), EllipsisLoc); + InitRange.getBegin(), Init, + InitRange.getEnd(), EllipsisLoc); } // C++ [base.class.init]p2: @@ -2323,8 +2336,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); - CXXBaseSpecifier *BaseSpec - = const_cast(DirectBaseSpec); + CXXBaseSpecifier *BaseSpec = const_cast(DirectBaseSpec); if (!BaseSpec) BaseSpec = const_cast(VirtualBaseSpec); @@ -2332,14 +2344,23 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = - InitializationKind::CreateDirect(BaseLoc, Args.getStartLoc(), - Args.getEndLoc()); - - ExprResult BaseInit = Args.PerformInit(*this, BaseEntity, Kind); + InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), + InitRange.getEnd()); + + Expr **Args = &Init; + unsigned NumArgs = 1; + if (ParenListExpr *ParenList = dyn_cast(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } + InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); + ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, + MultiExprArg(*this, Args, NumArgs), + 0); if (BaseInit.isInvalid()) return true; - CheckImplicitConversions(BaseInit.get(), Args.getStartLoc()); + CheckImplicitConversions(BaseInit.get(), InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -2356,13 +2377,13 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) - BaseInit = Owned(Args.CreateInitExpr(Context, BaseType)); + BaseInit = Owned(Init); return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), - Args.getStartLoc(), + InitRange.getBegin(), BaseInit.takeAs(), - Args.getEndLoc(), EllipsisLoc); + InitRange.getEnd(), EllipsisLoc); } // Create a static_cast\(expr). @@ -9064,7 +9085,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkFunctionReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - HadMultipleCandidates, RequiresZeroInit, + HadMultipleCandidates, /*FIXME*/false, + RequiresZeroInit, static_cast(ConstructKind), ParenRange)); } @@ -9116,187 +9138,6 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { Diag(VD->getLocation(), diag::warn_global_destructor); } -/// AddCXXDirectInitializerToDecl - This action is called immediately after -/// ActOnDeclarator, when a C++ direct initializer is present. -/// e.g: "int x(1);" -void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation RParenLoc, - bool TypeMayContainAuto) { - // If there is no declaration, there was an error parsing it. Just ignore - // the initializer. - if (RealDecl == 0) - return; - - VarDecl *VDecl = dyn_cast(RealDecl); - if (!VDecl) { - Diag(RealDecl->getLocation(), diag::err_illegal_initializer); - RealDecl->setInvalidDecl(); - return; - } - - // C++0x [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. - if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { - if (Exprs.size() == 0) { - // It isn't possible to write this directly, but it is possible to - // end up in this situation with "auto x(some_pack...);" - Diag(LParenLoc, diag::err_auto_var_init_no_expression) - << VDecl->getDeclName() << VDecl->getType() - << VDecl->getSourceRange(); - RealDecl->setInvalidDecl(); - return; - } - - if (Exprs.size() > 1) { - Diag(Exprs.get()[1]->getSourceRange().getBegin(), - diag::err_auto_var_init_multiple_expressions) - << VDecl->getDeclName() << VDecl->getType() - << VDecl->getSourceRange(); - RealDecl->setInvalidDecl(); - return; - } - - Expr *Init = Exprs.get()[0]; - TypeSourceInfo *DeducedType = 0; - if (DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType) == - DAR_Failed) - DiagnoseAutoDeductionFailure(VDecl, Init); - if (!DeducedType) { - RealDecl->setInvalidDecl(); - return; - } - VDecl->setTypeSourceInfo(DeducedType); - VDecl->setType(DeducedType->getType()); - - // In ARC, infer lifetime. - if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) - VDecl->setInvalidDecl(); - - // If this is a redeclaration, check that the type we just deduced matches - // the previously declared type. - if (VarDecl *Old = VDecl->getPreviousDecl()) - MergeVarDeclTypes(VDecl, Old); - } - - // We will represent direct-initialization similarly to copy-initialization: - // int x(1); -as-> int x = 1; - // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); - // - // Clients that want to distinguish between the two forms, can check for - // direct initializer using VarDecl::hasCXXDirectInitializer(). - // A major benefit is that clients that don't particularly care about which - // exactly form was it (like the CodeGen) can handle both cases without - // special case code. - - // C++ 8.5p11: - // The form of initialization (using parentheses or '=') is generally - // insignificant, but does matter when the entity being initialized has a - // class type. - - if (!VDecl->getType()->isDependentType() && - !VDecl->getType()->isIncompleteArrayType() && - RequireCompleteType(VDecl->getLocation(), VDecl->getType(), - diag::err_typecheck_decl_incomplete_type)) { - VDecl->setInvalidDecl(); - return; - } - - // The variable can not have an abstract class type. - if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), - diag::err_abstract_type_in_decl, - AbstractVariableType)) - VDecl->setInvalidDecl(); - - const VarDecl *Def; - if ((Def = VDecl->getDefinition()) && Def != VDecl) { - Diag(VDecl->getLocation(), diag::err_redefinition) - << VDecl->getDeclName(); - Diag(Def->getLocation(), diag::note_previous_definition); - VDecl->setInvalidDecl(); - return; - } - - // C++ [class.static.data]p4 - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition can - // specify a constant-initializer which shall be an integral - // constant expression (5.19). In that case, the member can appear - // in integral constant expressions. The member shall still be - // defined in a namespace scope if it is used in the program and the - // namespace scope definition shall not contain an initializer. - // - // We already performed a redefinition check above, but for static - // data members we also need to check whether there was an in-class - // declaration with an initializer. - const VarDecl* PrevInit = 0; - if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { - Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); - Diag(PrevInit->getLocation(), diag::note_previous_definition); - return; - } - - if (VDecl->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); - - bool IsDependent = false; - for (unsigned I = 0, N = Exprs.size(); I != N; ++I) { - if (DiagnoseUnexpandedParameterPack(Exprs.get()[I], UPPC_Expression)) { - VDecl->setInvalidDecl(); - return; - } - - if (Exprs.get()[I]->isTypeDependent()) - IsDependent = true; - } - - // If either the declaration has a dependent type or if any of the - // expressions is type-dependent, we represent the initialization - // via a ParenListExpr for later use during template instantiation. - if (VDecl->getType()->isDependentType() || IsDependent) { - // Let clients know that initialization was done with a direct initializer. - VDecl->setCXXDirectInitializer(true); - - // Store the initialization expressions as a ParenListExpr. - unsigned NumExprs = Exprs.size(); - VDecl->setInit(new (Context) ParenListExpr( - Context, LParenLoc, (Expr **)Exprs.release(), NumExprs, RParenLoc, - VDecl->getType().getNonReferenceType())); - return; - } - - // Capture the variable that is being initialized and the style of - // initialization. - InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); - - // FIXME: Poor source location information. - InitializationKind Kind - = InitializationKind::CreateDirect(VDecl->getLocation(), - LParenLoc, RParenLoc); - - QualType T = VDecl->getType(); - InitializationSequence InitSeq(*this, Entity, Kind, - Exprs.get(), Exprs.size()); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs), &T); - if (Result.isInvalid()) { - VDecl->setInvalidDecl(); - return; - } else if (T != VDecl->getType()) { - VDecl->setType(T); - Result.get()->setType(T); - } - - - Expr *Init = Result.get(); - CheckImplicitConversions(Init, LParenLoc); - - Init = MaybeCreateExprWithCleanups(Init); - VDecl->setInit(Init); - VDecl->setCXXDirectInitializer(true); - - CheckCompleteVariableDeclaration(VDecl); -} - /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index baf4d64872..946b2a07af 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2920,6 +2920,11 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, case tok::minusminus: Opc = UO_PostDec; break; } + // Since this might is a postfix expression, get rid of ParenListExprs. + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Input); + if (Result.isInvalid()) return ExprError(); + Input = Result.take(); + return BuildUnaryOp(S, OpLoc, Opc, Input); } @@ -4251,8 +4256,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); } -/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence -/// of comma binary operators. +/// This is not an AltiVec-style cast or or C++ direct-initialization, so turn +/// the ParenListExpr into a sequence of comma binary operators. ExprResult Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { ParenListExpr *E = dyn_cast(OrigExpr); @@ -4270,18 +4275,13 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get()); } -ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, - SourceLocation R, - MultiExprArg Val) { +ExprResult Sema::ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); - Expr *expr; - if (nexprs == 1) - expr = new (Context) ParenExpr(L, R, exprs[0]); - else - expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R, - exprs[nexprs-1]->getType()); + Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); return Owned(expr); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 32d1ec1c22..0532cdc392 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -4708,6 +4708,13 @@ InitializationSequence::Perform(Sema &S, } } + if (Kind.getKind() == InitializationKind::IK_Direct && + !Kind.isExplicitCast()) { + // Rebuild the ParenListExpr. + SourceRange ParenRange = Kind.getParenRange(); + return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(), + move(Args)); + } assert(Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast()); return ExprResult(Args.release()[0]); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 43aad09817..bd5a1ed3d0 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1833,14 +1833,16 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, FieldDecl *NewField = FieldsWithMemberInitializers[I].second; Expr *OldInit = OldField->getInClassInitializer(); - SourceLocation LParenLoc, RParenLoc; - ASTOwningVector NewArgs(*this); - if (InstantiateInitializer(OldInit, TemplateArgs, LParenLoc, NewArgs, - RParenLoc)) + ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, + /*CXXDirectInit=*/false); + if (NewInit.isInvalid()) NewField->setInvalidDecl(); else { - assert(NewArgs.size() == 1 && "wrong number of in-class initializers"); - ActOnCXXInClassMemberInitializer(NewField, LParenLoc, NewArgs[0]); + Expr *Init = NewInit.take(); + assert(Init && "no-argument initializer in class"); + assert(!isa(Init) && "call-style init in class"); + ActOnCXXInClassMemberInitializer(NewField, + Init->getSourceRange().getBegin(), Init); } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3cf816a332..7449c62fee 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -252,66 +252,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } -/// \brief Instantiate an initializer, breaking it into separate -/// initialization arguments. -/// -/// \param Init The initializer to instantiate. -/// -/// \param TemplateArgs Template arguments to be substituted into the -/// initializer. -/// -/// \param NewArgs Will be filled in with the instantiation arguments. -/// -/// \returns true if an error occurred, false otherwise -bool Sema::InstantiateInitializer(Expr *Init, - const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation &LParenLoc, - ASTOwningVector &NewArgs, - SourceLocation &RParenLoc) { - NewArgs.clear(); - LParenLoc = SourceLocation(); - RParenLoc = SourceLocation(); - - if (!Init) - return false; - - if (ExprWithCleanups *ExprTemp = dyn_cast(Init)) - Init = ExprTemp->getSubExpr(); - - while (CXXBindTemporaryExpr *Binder = dyn_cast(Init)) - Init = Binder->getSubExpr(); - - if (ImplicitCastExpr *ICE = dyn_cast(Init)) - Init = ICE->getSubExprAsWritten(); - - if (ParenListExpr *ParenList = dyn_cast(Init)) { - LParenLoc = ParenList->getLParenLoc(); - RParenLoc = ParenList->getRParenLoc(); - return SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), - true, TemplateArgs, NewArgs); - } - - if (CXXConstructExpr *Construct = dyn_cast(Init)) { - if (!isa(Construct)) { - if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, - TemplateArgs, NewArgs)) - return true; - - // FIXME: Fake locations! - LParenLoc = PP.getLocForEndOfToken(Init->getLocStart()); - RParenLoc = LParenLoc; - return false; - } - } - - ExprResult Result = SubstExpr(Init, TemplateArgs); - if (Result.isInvalid()) - return true; - - NewArgs.push_back(Result.takeAs()); - return false; -} - Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // If this is the variable for an anonymous struct or union, // instantiate the anonymous struct/union type first. @@ -342,7 +282,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { D->getStorageClass(), D->getStorageClassAsWritten()); Var->setThreadSpecified(D->isThreadSpecified()); - Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); + Var->setInitStyle(D->getInitStyle()); Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); Var->setConstexpr(D->isConstexpr()); @@ -403,25 +343,16 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); // Instantiate the initializer. - SourceLocation LParenLoc, RParenLoc; - ASTOwningVector InitArgs(SemaRef); - if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc, - InitArgs, RParenLoc)) { + ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs, + D->getInitStyle() == VarDecl::CallInit); + if (!Init.isInvalid()) { bool TypeMayContainAuto = true; - if (D->hasCXXDirectInitializer()) { - // Add the direct initializer to the declaration. - SemaRef.AddCXXDirectInitializerToDecl(Var, - LParenLoc, - move_arg(InitArgs), - RParenLoc, - TypeMayContainAuto); - } else if (InitArgs.size() == 0) { + if (Init.get()) { + bool DirectInit = D->isDirectInit(); + SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit, + TypeMayContainAuto); + } else SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto); - } else { - assert(InitArgs.size() == 1); - Expr *Init = InitArgs.take()[0]; - SemaRef.AddInitializerToDecl(Var, Init, false, TypeMayContainAuto); - } } else { // FIXME: Not too happy about invalidating the declaration // because of a bogus initializer. @@ -2743,18 +2674,6 @@ void Sema::InstantiateStaticDataMemberDefinition( } } -static MultiInitializer CreateMultiInitializer(SmallVectorImpl &Args, - const CXXCtorInitializer *Init) { - // FIXME: This is a hack that will do slightly the wrong thing for an - // initializer of the form foo({...}). - // The right thing to do would be to modify InstantiateInitializer to create - // the MultiInitializer. - if (Args.size() == 1 && isa(Args[0])) - return MultiInitializer(Args[0]); - return MultiInitializer(Init->getLParenLoc(), Args.data(), - Args.size(), Init->getRParenLoc()); -} - void Sema::InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, @@ -2774,9 +2693,6 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, if (!Init->isWritten()) continue; - SourceLocation LParenLoc, RParenLoc; - ASTOwningVector NewArgs(*this); - SourceLocation EllipsisLoc; if (Init->isPackExpansion()) { @@ -2804,8 +2720,9 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); // Instantiate the initializer. - if (InstantiateInitializer(Init->getInit(), TemplateArgs, - LParenLoc, NewArgs, RParenLoc)) { + ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs, + /*CXXDirectInit=*/true); + if (TempInit.isInvalid()) { AnyErrors = true; break; } @@ -2821,9 +2738,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, } // Build the initializer. - MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), - BaseTInfo, MultiInit, + BaseTInfo, TempInit.take(), New->getParent(), SourceLocation()); if (NewInit.isInvalid()) { @@ -2832,15 +2748,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, } NewInits.push_back(NewInit.get()); - NewArgs.clear(); } continue; } // Instantiate the initializer. - if (InstantiateInitializer(Init->getInit(), TemplateArgs, - LParenLoc, NewArgs, RParenLoc)) { + ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs, + /*CXXDirectInit=*/true); + if (TempInit.isInvalid()) { AnyErrors = true; continue; } @@ -2857,13 +2773,11 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } - MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); - if (Init->isBaseInitializer()) - NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, MultiInit, + NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, TempInit.take(), New->getParent(), EllipsisLoc); else - NewInit = BuildDelegatingInitializer(TInfo, MultiInit, + NewInit = BuildDelegatingInitializer(TInfo, TempInit.take(), cast(CurContext->getParent())); } else if (Init->isMemberInitializer()) { FieldDecl *Member = cast_or_null(FindInstantiatedDecl( @@ -2876,8 +2790,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } - MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); - NewInit = BuildMemberInitializer(Member, MultiInit, + NewInit = BuildMemberInitializer(Member, TempInit.take(), Init->getSourceLocation()); } else if (Init->isIndirectMemberInitializer()) { IndirectFieldDecl *IndirectMember = @@ -2891,8 +2804,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } - MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); - NewInit = BuildMemberInitializer(IndirectMember, MultiInit, + NewInit = BuildMemberInitializer(IndirectMember, TempInit.take(), Init->getSourceLocation()); } @@ -2900,9 +2812,6 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, AnyErrors = true; New->setInvalidDecl(); } else { - // FIXME: It would be nice if ASTOwningVector had a release function. - NewArgs.take(); - NewInits.push_back(NewInit.get()); } } @@ -2915,6 +2824,45 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, AnyErrors); } +ExprResult Sema::SubstInitializer(Expr *Init, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool CXXDirectInit) { + // Initializers are instantiated like expressions, except that various outer + // layers are stripped. + if (!Init) + return Owned(Init); + + if (ExprWithCleanups *ExprTemp = dyn_cast(Init)) + Init = ExprTemp->getSubExpr(); + + while (CXXBindTemporaryExpr *Binder = dyn_cast(Init)) + Init = Binder->getSubExpr(); + + if (ImplicitCastExpr *ICE = dyn_cast(Init)) + Init = ICE->getSubExprAsWritten(); + + // If this is a direct-initializer, we take apart CXXConstructExprs. + // Everything else is passed through. + CXXConstructExpr *Construct; + if (!CXXDirectInit || !(Construct = dyn_cast(Init)) || + isa(Construct)) + return SubstExpr(Init, TemplateArgs); + + ASTOwningVector NewArgs(*this); + if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, + TemplateArgs, NewArgs)) + return ExprError(); + + // Treat an empty initializer like none. + if (NewArgs.empty()) + return Owned((Expr*)0); + + // Build a ParenListExpr to represent anything else. + // FIXME: Fake locations! + SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart()); + return ActOnParenListExpr(Loc, Loc, move_arg(NewArgs)); +} + // TODO: this could be templated if the various decl types used the // same method name. static bool isInstantiationOf(ClassTemplateDecl *Pattern, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 4742bbfc96..8744f413a1 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1646,10 +1646,9 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildParenListExpr(SourceLocation LParenLoc, - MultiExprArg SubExprs, - SourceLocation RParenLoc) { - return getSema().ActOnParenOrParenListExpr(LParenLoc, RParenLoc, - move(SubExprs)); + MultiExprArg SubExprs, + SourceLocation RParenLoc) { + return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs)); } /// \brief Build a new address-of-label expression. diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 883edba5e3..e69fbe7a37 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -877,7 +877,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VD->VarDeclBits.SClass = (StorageClass)Record[Idx++]; VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++]; VD->VarDeclBits.ThreadSpecified = Record[Idx++]; - VD->VarDeclBits.HasCXXDirectInit = Record[Idx++]; + VD->VarDeclBits.InitStyle = Record[Idx++]; VD->VarDeclBits.ExceptionVar = Record[Idx++]; VD->VarDeclBits.NRVOVariable = Record[Idx++]; VD->VarDeclBits.CXXForRangeDecl = Record[Idx++]; diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 404eb88f59..7cd2f4ebed 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -656,7 +656,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->getStorageClass()); // FIXME: stable encoding Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->isThreadSpecified()); - Record.push_back(D->hasCXXDirectInitializer()); + Record.push_back(D->getInitStyle()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); Record.push_back(D->isCXXForRangeDecl()); @@ -688,7 +688,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && D->getFirstDeclaration() == D->getMostRecentDecl() && - !D->hasCXXDirectInitializer() && + D->getInitStyle() == VarDecl::CInit && D->getInit() == 0 && !isa(D) && !SpecInfo) @@ -728,7 +728,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { D->getAccess() == AS_none && !D->isModulePrivate() && D->getStorageClass() == 0 && - !D->hasCXXDirectInitializer() && // Can params have this ever? + D->getInitStyle() == VarDecl::CInit && // Can params have anything else? D->getFunctionScopeDepth() == 0 && D->getObjCDeclQualifier() == 0 && !D->isKNRPromoted() && diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index bbdf489796..6955219e7a 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -185,7 +185,7 @@ struct alignas(Types) TestUnexpandedDecls : T{ // expected-error{{expression con void test_initializers() { T copy_init = static_cast(0); // expected-error{{initializer contains unexpanded parameter pack 'Types'}} - T direct_init(0, static_cast(0)); // expected-error{{expression contains unexpanded parameter pack 'Types'}} + T direct_init(0, static_cast(0)); // expected-error{{initializer contains unexpanded parameter pack 'Types'}} T list_init = { static_cast(0) }; // expected-error{{initializer contains unexpanded parameter pack 'Types'}} } diff --git a/test/Sema/paren-list-expr-type.cpp b/test/Sema/paren-list-expr-type.cpp deleted file mode 100644 index ad5b7fbf91..0000000000 --- a/test/Sema/paren-list-expr-type.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clang -cc1 -ast-dump %s | not grep NULL -// Makes sure that we don't introduce null types when handling -// ParenListExpr. - -template class X { void f() { X x(*this); } }; - -template class Y { Y() : t(1) {} T t; }; - -template class Z { Z() : b(true) {} const bool b; }; - -template class A : public Z { A() : Z() {} }; - -class C {}; -template class D : public C { D(): C() {} }; - -void f() { (int)(1, 2); } - diff --git a/test/SemaTemplate/nested-incomplete-class.cpp b/test/SemaTemplate/nested-incomplete-class.cpp new file mode 100644 index 0000000000..a4bfccb8d2 --- /dev/null +++ b/test/SemaTemplate/nested-incomplete-class.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fsyntax-only %s + +template +struct foo { + struct bar; + + bar fn() { + // Should not get errors about bar being incomplete here. + bar b = bar(1, 2); + return b; + } +}; + +template +struct foo::bar { + bar(int, int); +}; + +void fn() { + foo().fn(); +} -- 2.40.0