From ca5233044ef679840d1ad1c46a36b16e2ee8a6e1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 10 Jun 2012 03:12:00 +0000 Subject: [PATCH] PR13064: Store whether an in-class initializer uses direct or copy initialization, and use that information to produce the right kind of initialization during template instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158288 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 59 +++++++++++------------- include/clang/AST/DeclObjC.h | 4 +- include/clang/Basic/Specifiers.h | 7 +++ include/clang/Sema/Sema.h | 8 ++-- lib/AST/ASTContext.cpp | 8 ++-- lib/AST/ASTImporter.cpp | 2 +- lib/AST/Decl.cpp | 9 ++-- lib/AST/DeclPrinter.cpp | 5 +- lib/CodeGen/CGObjCMac.cpp | 10 ++-- lib/CodeGen/CodeGenModule.cpp | 4 +- lib/Parse/ParseCXXInlineMethods.cpp | 4 +- lib/Parse/ParseDeclCXX.cpp | 21 +++++---- lib/Rewrite/RewriteModernObjC.cpp | 18 ++++---- lib/Rewrite/RewriteObjC.cpp | 11 ++--- lib/Sema/SemaDecl.cpp | 16 ++++--- lib/Sema/SemaDeclCXX.cpp | 20 ++++---- lib/Sema/SemaExpr.cpp | 2 +- lib/Sema/SemaExprCXX.cpp | 2 +- lib/Sema/SemaTemplateInstantiate.cpp | 4 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- lib/Serialization/ASTReaderDecl.cpp | 11 ++--- lib/Serialization/ASTWriterDecl.cpp | 12 +++-- test/PCH/cxx-member-init.cpp | 4 ++ test/SemaTemplate/instantiate-init.cpp | 15 +++++- 24 files changed, 143 insertions(+), 115 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index a7bf599636..69c4b37224 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2093,25 +2093,26 @@ class FieldDecl : public DeclaratorDecl { bool Mutable : 1; mutable unsigned CachedFieldIndex : 31; - /// \brief A pointer to either the in-class initializer for this field (if - /// the boolean value is false), or the bit width expression for this bit - /// field (if the boolean value is true). + /// \brief An InClassInitStyle value, and either a bit width expression (if + /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class + /// initializer for this field (otherwise). /// /// We can safely combine these two because in-class initializers are not /// permitted for bit-fields. /// - /// If the boolean is false and the initializer is null, then this field has - /// an in-class initializer which has not yet been parsed and attached. - llvm::PointerIntPair InitializerOrBitWidth; + /// If the InClassInitStyle is not ICIS_NoInit and the initializer is null, + /// then this field has an in-class initializer which has not yet been parsed + /// and attached. + llvm::PointerIntPair InitializerOrBitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, - bool HasInit) + InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable), CachedFieldIndex(0), - InitializerOrBitWidth(BW, !HasInit) { - assert(!(BW && HasInit) && "got initializer for bitfield"); + InitializerOrBitWidth(BW, InitStyle) { + assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); } public: @@ -2119,7 +2120,7 @@ public: SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, - bool HasInit); + InClassInitStyle InitStyle); static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2130,12 +2131,10 @@ public: /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } - /// \brief Set whether this field is mutable (C++ only). - void setMutable(bool M) { Mutable = M; } - /// isBitfield - Determines whether this field is a bitfield. bool isBitField() const { - return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer(); + return getInClassInitStyle() == ICIS_NoInit && + InitializerOrBitWidth.getPointer(); } /// @brief Determines whether this is an unnamed bitfield. @@ -2151,39 +2150,34 @@ public: return isBitField() ? InitializerOrBitWidth.getPointer() : 0; } unsigned getBitWidthValue(const ASTContext &Ctx) const; - void setBitWidth(Expr *BW) { - assert(!InitializerOrBitWidth.getPointer() && - "bit width or initializer already set"); - InitializerOrBitWidth.setPointer(BW); - InitializerOrBitWidth.setInt(1); - } - /// removeBitWidth - Remove the bitfield width from this member. - void removeBitWidth() { - assert(isBitField() && "no bit width to remove"); - InitializerOrBitWidth.setPointer(0); + + /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which + /// this field has. + InClassInitStyle getInClassInitStyle() const { + return static_cast(InitializerOrBitWidth.getInt()); } - /// hasInClassInitializer - Determine whether this member has a C++0x in-class + /// hasInClassInitializer - Determine whether this member has a C++11 in-class /// initializer. bool hasInClassInitializer() const { - return !InitializerOrBitWidth.getInt(); + return getInClassInitStyle() != ICIS_NoInit; } - /// getInClassInitializer - Get the C++0x in-class initializer for this + /// getInClassInitializer - Get the C++11 in-class initializer for this /// member, or null if one has not been set. If a valid declaration has an /// in-class initializer, but this returns null, then we have not parsed and /// attached it yet. Expr *getInClassInitializer() const { return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0; } - /// setInClassInitializer - Set the C++0x in-class initializer for this + /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. void setInClassInitializer(Expr *Init); - /// removeInClassInitializer - Remove the C++0x in-class initializer from this + /// removeInClassInitializer - Remove the C++11 in-class initializer from this /// member. void removeInClassInitializer() { - assert(!InitializerOrBitWidth.getInt() && "no initializer to remove"); + assert(hasInClassInitializer() && "no initializer to remove"); InitializerOrBitWidth.setPointer(0); - InitializerOrBitWidth.setInt(1); + InitializerOrBitWidth.setInt(ICIS_NoInit); } /// getParent - Returns the parent of this field declaration, which @@ -2202,6 +2196,9 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FieldDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// EnumConstantDecl - An instance of this object exists for each enum constant diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 14c30dc8bf..a7906cc75b 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1016,7 +1016,7 @@ private: QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, - /*Mutable=*/false, /*HasInit=*/false), + /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {} public: @@ -1074,7 +1074,7 @@ class ObjCAtDefsFieldDecl : public FieldDecl { QualType T, Expr *BW) : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, /*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ? - BW, /*Mutable=*/false, /*HasInit=*/false) {} + BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {} public: static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 9e71827b67..4b08c4d155 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -168,6 +168,13 @@ namespace clang { inline bool isLegalForVariable(StorageClass SC) { return true; } + + /// \brief In-class initialization styles for non-static data members. + enum InClassInitStyle { + ICIS_NoInit, ///< No in-class initializer. + ICIS_CopyInit, ///< Copy initialization. + ICIS_ListInit ///< Direct list-initialization. + }; } // end namespace clang #endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f0d3213bd3..43fbade8c1 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1420,13 +1420,15 @@ public: Declarator &D, Expr *BitfieldWidth); FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, - Declarator &D, Expr *BitfieldWidth, bool HasInit, + Declarator &D, Expr *BitfieldWidth, + InClassInitStyle InitStyle, AccessSpecifier AS); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitfieldWidth, bool HasInit, + bool Mutable, Expr *BitfieldWidth, + InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = 0); @@ -4141,7 +4143,7 @@ public: Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, - bool HasDeferredInit); + InClassInitStyle InitStyle); void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, Expr *Init); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 47b286233e..b2c3c5e1d4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3813,7 +3813,7 @@ QualType ASTContext::getCFConstantStringType() const { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -3857,7 +3857,7 @@ QualType ASTContext::getBlockDescriptorType() const { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3900,7 +3900,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3976,7 +3976,7 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 9f016fe9bb..d8550eb0f2 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2662,7 +2662,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, BitWidth, D->isMutable(), - D->hasInClassInitializer()); + D->getInClassInitStyle()); ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); if (ToField->hasInClassInitializer()) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ee90b23e5c..3a00291816 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2465,15 +2465,15 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, - bool HasInit) { + InClassInitStyle InitStyle) { return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, - BW, Mutable, HasInit); + BW, Mutable, InitStyle); } FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FieldDecl)); return new (Mem) FieldDecl(Field, 0, SourceLocation(), SourceLocation(), - 0, QualType(), 0, 0, false, false); + 0, QualType(), 0, 0, false, ICIS_NoInit); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -2525,10 +2525,9 @@ SourceRange FieldDecl::getSourceRange() const { } void FieldDecl::setInClassInitializer(Expr *Init) { - assert(!InitializerOrBitWidth.getPointer() && + assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() && "bit width or initializer already set"); InitializerOrBitWidth.setPointer(Init); - InitializerOrBitWidth.setInt(0); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 6d4eaa3517..10f38942a5 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -582,7 +582,10 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { Expr *Init = D->getInClassInitializer(); if (!Policy.SuppressInitializers && Init) { - Out << " = "; + if (D->getInClassInitStyle() == ICIS_ListInit) + Out << " "; + else + Out << " = "; Init->printPretty(Out, Context, 0, Policy, Indentation); } prettyPrintAttributes(D); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 9b9ef79715..9a90995ba6 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -4386,9 +4386,10 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) SourceLocation(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCIdType(), 0, 0, false, false)); + Ctx.getObjCIdType(), 0, 0, false, ICIS_NoInit)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCClassType(), 0, 0, false, false)); + Ctx.getObjCClassType(), 0, 0, false, + ICIS_NoInit)); RD->completeDefinition(); SuperCTy = Ctx.getTagDeclType(RD); @@ -4767,9 +4768,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul SourceLocation(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.VoidPtrTy, 0, 0, false, false)); + Ctx.VoidPtrTy, 0, 0, false, ICIS_NoInit)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCSelType(), 0, 0, false, false)); + Ctx.getObjCSelType(), 0, 0, false, + ICIS_NoInit)); RD->completeDefinition(); MessageRefCTy = Ctx.getTagDeclType(RD); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index e9ae98ff39..e64a20403c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2127,7 +2127,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); } @@ -2202,7 +2202,7 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); } diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index d623abcff9..131c6b6546 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -46,7 +46,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VS, /*HasDeferredInit=*/false); + VS, ICIS_NoInit); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); @@ -493,7 +493,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); SourceLocation EqualLoc; - + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c75e138f61..88aa3982fb 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1991,18 +1991,19 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); - bool HasDeferredInitializer = false; + InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); } else { HasInitializer = true; - HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_static && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef; + if (!DeclaratorInfo.isDeclarationOfFunction() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) + HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } } @@ -2020,7 +2021,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - VS, HasDeferredInitializer); + VS, HasInClassInit); if (AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); @@ -2036,15 +2037,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Handle the initializer. - if (HasDeferredInitializer) { + if (HasInClassInit != ICIS_NoInit) { // The initializer was deferred; parse it and cache the tokens. Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nonstatic_member_init : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { - // C++0x [dcl.array]p3: An array bound may also be omitted when the - // declarator is followed by an initializer. + // C++11 [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. // // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp index 644ac57a94..61afaca9a4 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/RewriteModernObjC.cpp @@ -823,7 +823,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { &Context->Idents.get(D->getNameAsString()), IvarT, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -2720,7 +2720,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { &Context->Idents.get("arr"), Context->getPointerType(Context->VoidPtrTy), 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ArrayLiteralME = new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, SourceLocation(), @@ -2867,7 +2867,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral &Context->Idents.get("arr"), Context->getPointerType(Context->VoidPtrTy), 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *DictLiteralValueME = new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, SourceLocation(), @@ -3014,7 +3014,7 @@ QualType RewriteModernObjC::getSuperStructType() { FieldTypes[i], 0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false)); + ICIS_NoInit)); } SuperStructDecl->completeDefinition(); @@ -3047,7 +3047,7 @@ QualType RewriteModernObjC::getConstantStringStructType() { FieldTypes[i], 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false)); + ICIS_NoInit)); } ConstantStringDecl->completeDefinition(); @@ -4491,7 +4491,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -4540,7 +4540,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -4551,7 +4551,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get(Name), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); @@ -7436,7 +7436,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { &Context->Idents.get(D->getNameAsString()), IvarT, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 6c7b20befd..678a4cf9d0 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -2592,7 +2592,7 @@ QualType RewriteObjC::getSuperStructType() { FieldTypes[i], 0, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false)); + ICIS_NoInit)); } SuperStructDecl->completeDefinition(); @@ -2625,7 +2625,7 @@ QualType RewriteObjC::getConstantStringStructType() { FieldTypes[i], 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false)); + ICIS_NoInit)); } ConstantStringDecl->completeDefinition(); @@ -3887,7 +3887,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -3936,7 +3936,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -3947,7 +3947,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get(Name), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true, - /*HasInit=*/false); + ICIS_NoInit); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); @@ -6015,4 +6015,3 @@ Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { ReplaceStmtWithRange(IV, Replacement, OldRange); return Replacement; } - diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 40cc35117c..9ad8c30505 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2969,7 +2969,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); if (getLangOpts().CPlusPlus) FieldCollector->Add(cast(Anon)); @@ -3066,7 +3066,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false, - /*HasInit=*/false); + /*InitStyle=*/ICIS_NoInit); Anon->setImplicit(); // Add the anonymous struct object to the current context. @@ -8975,7 +8975,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null(TagD), DeclStart, D, static_cast(BitfieldWidth), - /*HasInit=*/false, AS_public); + /*InitStyle=*/ICIS_NoInit, AS_public); return Res; } @@ -8983,7 +8983,8 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, - Declarator &D, Expr *BitWidth, bool HasInit, + Declarator &D, Expr *BitWidth, + InClassInitStyle InitStyle, AccessSpecifier AS) { IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; @@ -9045,7 +9046,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getLocStart(); FieldDecl *NewFD - = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit, + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, InitStyle, TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) @@ -9078,7 +9079,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitWidth, bool HasInit, + bool Mutable, Expr *BitWidth, + InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { @@ -9168,7 +9170,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, - BitWidth, Mutable, HasInit); + BitWidth, Mutable, InitStyle); if (InvalidDecl) NewFD->setInvalidDecl(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2b7d1bfcd8..4fd3a03cfd 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1453,13 +1453,13 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if -/// one has been parsed, and 'HasDeferredInit' is true if an initializer is -/// present but parsing it has been deferred. +/// one has been parsed, and 'InitStyle' is set if an in-class initializer is +/// present (but parsing it has been deferred). Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BW, const VirtSpecifiers &VS, - bool HasDeferredInit) { + InClassInitStyle InitStyle) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1563,10 +1563,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } Member = HandleField(S, cast(CurContext), Loc, D, BitWidth, - HasDeferredInit, AS); + InitStyle, AS); assert(Member && "HandleField never returns null"); } else { - assert(!HasDeferredInit); + assert(InitStyle == ICIS_NoInit); Member = HandleDeclarator(S, D, move(TemplateParameterLists)); if (!Member) { @@ -1660,9 +1660,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, /// instantiating an in-class initializer in a class template. Such actions /// are deferred until the class is complete. void -Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, +Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, Expr *InitExpr) { FieldDecl *FD = cast(D); + assert(FD->getInClassInitStyle() != ICIS_NoInit && + "must set init style when field is created"); if (!InitExpr) { FD->setInvalidDecl(); @@ -1685,9 +1687,9 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, Expr **Inits = &InitExpr; unsigned NumInits = 1; InitializedEntity Entity = InitializedEntity::InitializeMember(FD); - InitializationKind Kind = EqualLoc.isInvalid() + InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) - : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc); + : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits); Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (Init.isInvalid()) { @@ -1695,7 +1697,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, return; } - CheckImplicitConversions(Init.get(), EqualLoc); + CheckImplicitConversions(Init.get(), InitLoc); } // C++0x [class.base.init]p7: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8423a2d97f..0ca46d0505 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10206,7 +10206,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, FieldDecl *Field = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType, S.Context.getTrivialTypeSourceInfo(FieldType, Loc), - 0, false, false); + 0, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d1567c8d6c..03c49f93bd 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -740,7 +740,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { FieldDecl *Field = FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy, Context.getTrivialTypeSourceInfo(ThisTy, Loc), - 0, false, false); + 0, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index dc0f288c50..866b9fc11d 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1963,9 +1963,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, 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); + ActOnCXXInClassMemberInitializer(NewField, Init->getLocStart(), Init); } } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9ff6a490d6..4f795be17a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -430,7 +430,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { D->getLocation(), D->isMutable(), BitWidth, - D->hasInClassInitializer(), + D->getInClassInitStyle(), D->getInnerLocStart(), D->getAccess(), 0); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index cfafc1c6b8..cb14adf439 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -865,12 +865,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); - FD->setMutable(Record[Idx++]); - int BitWidthOrInitializer = Record[Idx++]; - if (BitWidthOrInitializer == 1) - FD->setBitWidth(Reader.ReadExpr(F)); - else if (BitWidthOrInitializer == 2) - FD->setInClassInitializer(Reader.ReadExpr(F)); + FD->Mutable = Record[Idx++]; + if (int BitWidthOrInitializer = Record[Idx++]) { + FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1); + FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F)); + } if (!FD->getDeclName()) { if (FieldDecl *Tmpl = ReadDeclAs(Record, Idx)) Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 86b667ad71..d4ebc1c42a 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -626,11 +626,13 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0); - if (D->getBitWidth()) - Writer.AddStmt(D->getBitWidth()); - else if (D->hasInClassInitializer()) - Writer.AddStmt(D->getInClassInitializer()); + if (D->InitializerOrBitWidth.getInt() != ICIS_NoInit || + D->InitializerOrBitWidth.getPointer()) { + Record.push_back(D->InitializerOrBitWidth.getInt() + 1); + Writer.AddStmt(D->InitializerOrBitWidth.getPointer()); + } else { + Record.push_back(0); + } if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); diff --git a/test/PCH/cxx-member-init.cpp b/test/PCH/cxx-member-init.cpp index 28206652b8..20594d532e 100644 --- a/test/PCH/cxx-member-init.cpp +++ b/test/PCH/cxx-member-init.cpp @@ -12,10 +12,14 @@ struct S { int &m = n; S *that = this; }; +template struct X { T t {0}; }; #endif #ifdef SOURCE S s; + +struct E { explicit E(int); }; +X x; #elif HEADER #undef HEADER #define SOURCE diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp index f0ca9a5b21..612a0b7f62 100644 --- a/test/SemaTemplate/instantiate-init.cpp +++ b/test/SemaTemplate/instantiate-init.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -struct X0 { // expected-note 4{{candidate}} +struct X0 { // expected-note 8{{candidate}} X0(int*, float*); // expected-note 4{{candidate}} }; @@ -107,3 +107,14 @@ namespace PR7985 { array_lengthof(Description::data); // expected-error{{no matching function for call to 'array_lengthof'}} } } + +namespace PR13064 { + // Ensure that in-class direct-initialization is instantiated as + // direct-initialization and likewise copy-initialization is instantiated as + // copy-initialization. + struct A { explicit A(int); }; // expected-note{{here}} + template struct B { T a { 0 }; }; + B b; + template struct C { T a = { 0 }; }; // expected-error{{explicit}} + C c; // expected-note{{here}} +} -- 2.50.1