From: Douglas Gregor Date: Fri, 4 Feb 2011 12:01:24 +0000 (+0000) Subject: Implement proper (de-)serialization for explicit template argument X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=def0354384d9c4431f7b58b664b59896d4623028;p=clang Implement proper (de-)serialization for explicit template argument lists with zero template arguments. Fixes some seriously scary crashers in C++ PCH. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124862 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index e718961866..cf1faf1aff 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -668,7 +668,9 @@ public: /// \brief Construct an empty declaration reference expression. static DeclRefExpr *CreateEmpty(ASTContext &Context, - bool HasQualifier, unsigned NumTemplateArgs); + bool HasQualifier, + bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); ValueDecl *getDecl() { return DecoratedD.getPointer(); } const ValueDecl *getDecl() const { return DecoratedD.getPointer(); } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index addf35a1bc..7c8ac95203 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1762,6 +1762,7 @@ public: UnresolvedSetIterator End); static UnresolvedLookupExpr *CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs); /// True if this declaration should be extended by @@ -1883,6 +1884,7 @@ public: const TemplateArgumentListInfo *TemplateArgs = 0); static DependentScopeDeclRefExpr *CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs); /// \brief Retrieve the name that this expression refers to. @@ -2223,7 +2225,8 @@ public: const TemplateArgumentListInfo *TemplateArgs); static CXXDependentScopeMemberExpr * - CreateEmpty(ASTContext &C, unsigned NumTemplateArgs); + CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source @@ -2445,7 +2448,8 @@ public: UnresolvedSetIterator Begin, UnresolvedSetIterator End); static UnresolvedMemberExpr * - CreateEmpty(ASTContext &C, unsigned NumTemplateArgs); + CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9e8f801791..04498f7b9a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -319,13 +319,15 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, TemplateArgs, T, VK); } -DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, bool HasQualifier, +DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, + bool HasQualifier, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (HasQualifier) Size += sizeof(NameQualifier); - if (NumTemplateArgs) + if (HasExplicitTemplateArgs) Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignOf()); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 7cd714ba3f..a11d05a3a7 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -265,14 +265,15 @@ UnresolvedLookupExpr::Create(ASTContext &C, } UnresolvedLookupExpr * -UnresolvedLookupExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { +UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedLookupExpr); - if (NumTemplateArgs != 0) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf()); UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); - E->HasExplicitTemplateArgs = NumTemplateArgs != 0; + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; return E; } @@ -417,13 +418,17 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, DependentScopeDeclRefExpr * DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t size = sizeof(DependentScopeDeclRefExpr); - if (NumTemplateArgs) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size); - return new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(), - DeclarationNameInfo(), 0); + DependentScopeDeclRefExpr *E + = new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(), + DeclarationNameInfo(), 0); + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; + return E; } StmtIterator DependentScopeDeclRefExpr::child_begin() { @@ -902,8 +907,9 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { - if (NumTemplateArgs == 0) + if (!HasExplicitTemplateArgs) return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(), 0, SourceLocation(), 0, SourceRange(), 0, @@ -978,14 +984,15 @@ UnresolvedMemberExpr::Create(ASTContext &C, } UnresolvedMemberExpr * -UnresolvedMemberExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { +UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedMemberExpr); - if (NumTemplateArgs != 0) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf()); UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); - E->HasExplicitTemplateArgs = NumTemplateArgs != 0; + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; return E; } diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index c704eb2ab4..4335ff9706 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -419,19 +419,22 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); bool HasQualifier = Record[Idx++]; - unsigned NumTemplateArgs = Record[Idx++]; + bool HasExplicitTemplateArgs = Record[Idx++]; E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) | - (NumTemplateArgs ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0)); + (HasExplicitTemplateArgs + ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0)); if (HasQualifier) { E->getNameQualifier()->NNS = Reader.ReadNestedNameSpecifier(Record, Idx); E->getNameQualifier()->Range = ReadSourceRange(Record, Idx); } - if (NumTemplateArgs) + if (HasExplicitTemplateArgs) { + unsigned NumTemplateArgs = Record[Idx++]; ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), NumTemplateArgs); + } E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); E->setLocation(ReadSourceLocation(Record, Idx)); @@ -1180,12 +1183,9 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ VisitExpr(E); - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) + if (Record[Idx++]) ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), - NumTemplateArgs); + Record[Idx++]); E->setBase(Reader.ReadSubExpr()); E->setBaseType(Reader.GetType(Record[Idx++])); @@ -1202,13 +1202,10 @@ void ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { VisitExpr(E); - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) - ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), - NumTemplateArgs); - + if (Record[Idx++]) + ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), + Record[Idx++]); + ReadDeclarationNameInfo(E->NameInfo, Record, Idx); E->setQualifierRange(ReadSourceRange(Record, Idx)); E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); @@ -1229,12 +1226,10 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { VisitExpr(E); - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) + // Read the explicit template argument list, if available. + if (Record[Idx++]) ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), - NumTemplateArgs); + Record[Idx++]); unsigned NumDecls = Record[Idx++]; UnresolvedSet<8> Decls; @@ -1484,7 +1479,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_DECL_REF: S = DeclRefExpr::CreateEmpty(*Context, /*HasQualifier=*/Record[ASTStmtReader::NumExprFields], - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1]); + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1] + ? Record[ASTStmtReader::NumExprFields + 2] + : 0); break; case EXPR_INTEGER_LITERAL: @@ -1552,8 +1550,9 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { } TemplateArgumentListInfo ArgInfo; - unsigned NumTemplateArgs = Record[Idx++]; - if (NumTemplateArgs) { + bool HasExplicitTemplateArgs = Record[Idx++]; + if (HasExplicitTemplateArgs) { + unsigned NumTemplateArgs = Record[Idx++]; ArgInfo.setLAngleLoc(ReadSourceLocation(F, Record, Idx)); ArgInfo.setRAngleLoc(ReadSourceLocation(F, Record, Idx)); for (unsigned i = 0; i != NumTemplateArgs; ++i) @@ -1575,7 +1574,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = MemberExpr::Create(*Context, Base, IsArrow, NNS, QualifierRange, MemberD, FoundDecl, MemberNameInfo, - NumTemplateArgs ? &ArgInfo : 0, T, VK, OK); + HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK); ReadDeclarationNameLoc(F, cast(S)->MemberDNLoc, MemberD->getDeclName(), Record, Idx); break; @@ -1812,12 +1811,18 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: S = CXXDependentScopeMemberExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]); + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] + ? Record[ASTStmtReader::NumExprFields + 1] + : 0); break; case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: S = DependentScopeDeclRefExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]); + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] + ? Record[ASTStmtReader::NumExprFields + 1] + : 0); break; case EXPR_CXX_UNRESOLVED_CONSTRUCT: @@ -1827,12 +1832,18 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_CXX_UNRESOLVED_MEMBER: S = UnresolvedMemberExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]); + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] + ? Record[ASTStmtReader::NumExprFields + 1] + : 0); break; case EXPR_CXX_UNRESOLVED_LOOKUP: S = UnresolvedLookupExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]); + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] + ? Record[ASTStmtReader::NumExprFields + 1] + : 0); break; case EXPR_CXX_UNARY_TYPE_TRAIT: diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 15a3670167..4a3bea5aae 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -379,18 +379,18 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); Record.push_back(E->hasQualifier()); - unsigned NumTemplateArgs = E->getNumTemplateArgs(); - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Template args list with no args ?"); - Record.push_back(NumTemplateArgs); + Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasQualifier()) { Writer.AddNestedNameSpecifier(E->getQualifier(), Record); Writer.AddSourceRange(E->getQualifierRange(), Record); } - if (NumTemplateArgs) + if (E->hasExplicitTemplateArgs()) { + unsigned NumTemplateArgs = E->getNumTemplateArgs(); + Record.push_back(NumTemplateArgs); AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs()); + } Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); @@ -545,11 +545,10 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) { Writer.AddSourceRange(E->getQualifierRange(), Record); } - unsigned NumTemplateArgs = E->getNumTemplateArgs(); - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Template args list with no args ?"); - Record.push_back(NumTemplateArgs); - if (NumTemplateArgs) { + Record.push_back(E->hasExplicitTemplateArgs()); + if (E->hasExplicitTemplateArgs()) { + unsigned NumTemplateArgs = E->getNumTemplateArgs(); + Record.push_back(NumTemplateArgs); Writer.AddSourceLocation(E->getLAngleLoc(), Record); Writer.AddSourceLocation(E->getRAngleLoc(), Record); for (unsigned i=0; i != NumTemplateArgs; ++i) @@ -1169,16 +1168,14 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ VisitExpr(E); - // Don't emit anything here, NumTemplateArgs must be emitted first. + // Don't emit anything here, hasExplicitTemplateArgs() must be + // emitted first. + Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! AST reading will mess up!"); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); } if (!E->isImplicitAccess()) @@ -1199,16 +1196,13 @@ void ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { VisitExpr(E); - // Don't emit anything here, NumTemplateArgs must be emitted first. - + // Don't emit anything here, hasExplicitTemplateArgs() must be + // emitted first. + Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! AST reading will mess up!"); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); } Writer.AddDeclarationNameInfo(E->NameInfo, Record); @@ -1233,16 +1227,12 @@ ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) { VisitExpr(E); - // Don't emit anything here, NumTemplateArgs must be emitted first. - + // Don't emit anything here, hasExplicitTemplateArgs() must be emitted first. + Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! AST reading will mess up!"); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); } Record.push_back(E->getNumDecls()); diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 56b8ab7399..e2ad46c659 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -39,3 +39,7 @@ void test(const int (&a6)[17]) { template struct S4; S7 s7_5; + +namespace ZeroLengthExplicitTemplateArgs { + template void f(X*); +} diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h index ec8becbdc9..d2c820f877 100644 --- a/test/PCH/cxx-templates.h +++ b/test/PCH/cxx-templates.h @@ -169,3 +169,27 @@ template template struct S7 : S6 { }; + +// Zero-length template argument lists +namespace ZeroLengthExplicitTemplateArgs { + template void h(); + + struct Y { + template void f(); + }; + + template + void f(T *ptr) { + T::template g<>(17); + ptr->template g2<>(17); + h(); + h(); + Y y; + y.f(); + } + + struct X { + template static void g(T); + template void g2(T); + }; +}