From c7793c73ba8a343de3f2552d984851985a46f159 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 15 Jan 2011 01:15:58 +0000 Subject: [PATCH] Introduce a new expression kind, SubstNonTypeTemplateParmPackExpr, that captures the substitution of a non-type template argument pack for a non-type template parameter pack within a pack expansion that cannot be fully expanded. This follows the approach taken by SubstTemplateTypeParmPackType. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123506 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 65 ++++++++++++++++++- include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/Basic/StmtNodes.td | 1 + include/clang/Serialization/ASTBitCodes.h | 3 +- lib/AST/ExprCXX.cpp | 28 ++++++++ lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 1 + lib/AST/ItaniumMangle.cpp | 5 ++ lib/AST/StmtPrinter.cpp | 6 ++ lib/AST/StmtProfile.cpp | 7 ++ lib/Sema/SemaTemplateInstantiate.cpp | 56 ++++++++++++++-- lib/Sema/TreeTransform.h | 8 +++ lib/Serialization/ASTReaderStmt.cpp | 22 ++++++- lib/Serialization/ASTWriterStmt.cpp | 12 ++++ lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 1 + .../multi-level-substitution.cpp | 23 +++++++ tools/libclang/CIndex.cpp | 3 + tools/libclang/CXCursor.cpp | 1 + 18 files changed, 237 insertions(+), 7 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index abc8c77a38..f6bbfbf361 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -2746,7 +2746,8 @@ public: /// \brief Retrieve the length of the parameter pack. /// - /// This routine may only be invoked when + /// This routine may only be invoked when the expression is not + /// value-dependent. unsigned getPackLength() const { assert(!isValueDependent() && "Cannot get the length of a value-dependent pack size expression"); @@ -2764,6 +2765,68 @@ public: virtual child_iterator child_begin(); virtual child_iterator child_end(); }; + +/// \brief Represents a reference to a non-type template parameter pack that +/// has been substituted with a non-template argument pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this node node is used to represent a non-type template +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the appropriate underlying +/// expression at the current pack substitution index. +class SubstNonTypeTemplateParmPackExpr : public Expr { + /// \brief The non-type template parameter pack itself. + NonTypeTemplateParmDecl *Param; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + /// \brief The location of the non-type template parameter pack reference. + SourceLocation NameLoc; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack); + + SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } + + /// \brief Retrieve the non-type template parameter pack being substituted. + NonTypeTemplateParmDecl *getParameterPack() const { return Param; } + + /// \brief Retrieve the location of the parameter pack name. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Retrieve the template argument pack containing the substituted + /// template arguments. + TemplateArgument getArgumentPack() const; + + virtual SourceRange getSourceRange() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass; + } + static bool classof(const SubstNonTypeTemplateParmPackExpr *) { + return true; + } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; } // end namespace clang diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 3d1279b252..532759b033 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1856,6 +1856,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, { }) DEF_TRAVERSE_STMT(CXXNoexceptExpr, { }) DEF_TRAVERSE_STMT(PackExpansionExpr, { }) DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, { }) diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 9322db12c5..58db87b4c2 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -113,6 +113,7 @@ def UnresolvedMemberExpr : DStmt; def CXXNoexceptExpr : DStmt; def PackExpansionExpr : DStmt; def SizeOfPackExpr : DStmt; +def SubstNonTypeTemplateParmPackExpr : DStmt; // Obj-C Expressions. def ObjCStringLiteral : DStmt; diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 6ef4dbeb0c..7a9019f384 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -936,7 +936,8 @@ namespace clang { EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr EXPR_PACK_EXPANSION, // PackExpansionExpr - EXPR_SIZEOF_PACK // SizeOfPackExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK // SubstNonTypeTemplateParmPackExpr }; /// \brief The kinds of designators that can occur in a diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 0426e59a74..2c790bd273 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -1056,3 +1056,31 @@ Stmt::child_iterator SizeOfPackExpr::child_begin() { Stmt::child_iterator SizeOfPackExpr::child_end() { return child_iterator(); } + +SubstNonTypeTemplateParmPackExpr:: +SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack) + : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, + true, false, true), + Param(Param), Arguments(ArgPack.pack_begin()), + NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { } + +TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); +} + +SourceRange SubstNonTypeTemplateParmPackExpr::getSourceRange() const { + return NameLoc; +} + +Stmt::child_iterator SubstNonTypeTemplateParmPackExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator SubstNonTypeTemplateParmPackExpr::child_end() { + return child_iterator(); +} + + diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index a9ebe6fdb3..c9f4fa8daa 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -152,6 +152,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ParenListExprClass: case Expr::InitListExprClass: case Expr::SizeOfPackExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: return Cl::CL_PRValue; // Next come the complicated cases. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 57ceb3f481..cb73810163 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -2645,6 +2645,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::NoStmtClass: case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0ebd7da679..2f8be294f2 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1948,6 +1948,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { break; } + case Expr::SubstNonTypeTemplateParmPackExprClass: + mangleTemplateParameter( + cast(E)->getParameterPack()->getIndex()); + break; + case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast(E); NestedNameSpecifier *NNS = DRE->getQualifier(); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 2c8504357e..4c18a526bb 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -15,6 +15,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Format.h" #include "clang/AST/Expr.h" @@ -1255,6 +1256,11 @@ void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { OS << "sizeof...(" << E->getPack()->getNameAsString() << ")"; } +void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *Node) { + OS << Node->getParameterPack()->getNameAsString(); +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 232f48e1ee..e75c274015 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -841,6 +841,13 @@ void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) { VisitDecl(S->getPack()); } +void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + VisitTemplateArgument(S->getArgumentPack()); +} + void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 17b38bc1de..8943daa369 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -702,7 +702,9 @@ namespace { ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); - + ExprResult TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, @@ -924,9 +926,19 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, "Missing argument pack"); if (getSema().ArgumentPackSubstitutionIndex == -1) { - // FIXME: Variadic templates fun case. - getSema().Diag(Loc, diag::err_pack_expansion_mismatch_unsupported); - return ExprError(); + // We have an argument pack, but we can't select a particular argument + // out of it yet. Therefore, we'll build an expression to hold on to that + // argument pack. + QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, + E->getLocation(), + NTTP->getDeclName()); + if (TargetType.isNull()) + return ExprError(); + + return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr(TargetType, + NTTP, + E->getLocation(), + Arg); } assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); @@ -965,6 +977,42 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, E->getSourceRange().getBegin()); } +ExprResult +TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We aren't expanding the parameter pack, so just return ourselves. + return getSema().Owned(E); + } + + // FIXME: Variadic templates select Nth from type? + const TemplateArgument &ArgPack = E->getArgumentPack(); + unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex; + assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); + + const TemplateArgument &Arg = ArgPack.pack_begin()[Index]; + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()); + + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast(Arg.getAsDecl()); + + // Find the instantiation of the template argument. This is + // required for nested templates. + VD = cast_or_null( + getSema().FindInstantiatedDecl(E->getParameterPackLocation(), + VD, TemplateArgs)); + if (!VD) + return ExprError(); + + return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, + E->getType(), + E->getParameterPackLocation()); + } + + return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, + E->getParameterPackLocation()); +} ExprResult TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 02c95bdb13..73982a71c2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6892,6 +6892,14 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { *NumExpansions); } +template +ExprResult +TreeTransform::TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + template ExprResult TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 022b619412..5fec238ab8 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -14,6 +14,7 @@ #include "clang/Serialization/ASTReader.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" using namespace clang; using namespace clang::serialization; @@ -178,7 +179,8 @@ namespace clang { void VisitCXXNoexceptExpr(CXXNoexceptExpr *E); void VisitPackExpansionExpr(PackExpansionExpr *E); void VisitSizeOfPackExpr(SizeOfPackExpr *E); - + void VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E); void VisitOpaqueValueExpr(OpaqueValueExpr *E); }; } @@ -1307,6 +1309,20 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { E->Pack = cast_or_null(Reader.GetDecl(Record[Idx++])); } +void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + VisitExpr(E); + E->Param + = cast_or_null(Reader.GetDecl(Record[Idx++])); + TemplateArgument ArgPack = Reader.ReadTemplateArgument(F, Record, Idx); + if (ArgPack.getKind() != TemplateArgument::Pack) + return; + + E->Arguments = ArgPack.pack_begin(); + E->NumArguments = ArgPack.pack_size(); + E->NameLoc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); } @@ -1837,6 +1853,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) SizeOfPackExpr(Empty); break; + case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK: + S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty); + break; + case EXPR_OPAQUE_VALUE: S = new (Context) OpaqueValueExpr(Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 205f4dc2a9..e03a780fad 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -14,6 +14,7 @@ #include "clang/Serialization/ASTWriter.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" #include "llvm/Bitcode/BitstreamWriter.h" using namespace clang; @@ -152,6 +153,8 @@ namespace clang { void VisitCXXNoexceptExpr(CXXNoexceptExpr *E); void VisitPackExpansionExpr(PackExpansionExpr *E); void VisitSizeOfPackExpr(SizeOfPackExpr *E); + void VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E); void VisitOpaqueValueExpr(OpaqueValueExpr *E); }; } @@ -1316,6 +1319,15 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { Code = serialization::EXPR_SIZEOF_PACK; } +void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->Param, Record); + Writer.AddTemplateArgument(E->getArgumentPack(), Record); + Writer.AddSourceLocation(E->NameLoc, Record); + Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK; +} + void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); Code = serialization::EXPR_OPAQUE_VALUE; diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index f3c305a388..f45041b73e 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -789,6 +789,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::UnresolvedMemberExprClass: case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: + case Stmt::SubstNonTypeTemplateParmPackExprClass: { SaveAndRestore OldSink(Builder->BuildSinks); Builder->BuildSinks = true; diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index 5ce5e63adb..01d5759188 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -126,4 +126,27 @@ namespace PacksAtDifferentLevels { some_function_object::result_of, some_function_object::result_of> >::value == 0? 1 : -1]; + + template struct unsigned_pair { }; + + template + struct X4 { + template struct Inner { + static const unsigned value = 0; + }; + + template + struct Inner...>> { + static const unsigned value = 1; + }; + }; + + int check8[X4<1, 3, 5>::Inner, + unsigned_pair<3, 4>, + unsigned_pair<5, 6>> + >::value == 1? 1 : -1]; + int check9[X4<1, 3>::Inner, + unsigned_pair<3, 4>, + unsigned_pair<5, 6>> + >::value == 0? 1 : -1]; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 38b86cd23f..574b4c8b4e 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2649,6 +2649,9 @@ static Decl *getDeclFromExpr(Stmt *E) { if (ObjCProtocolExpr *PE = dyn_cast(E)) return PE->getProtocol(); + if (SubstNonTypeTemplateParmPackExpr *NTTP + = dyn_cast(E)) + return NTTP->getParameterPack(); return 0; } diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 1a75284de3..7bcd1597ba 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -171,6 +171,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::DeclRefExprClass: case Stmt::BlockDeclRefExprClass: + case Stmt::SubstNonTypeTemplateParmPackExprClass: // FIXME: UnresolvedLookupExpr? // FIXME: DependentScopeDeclRefExpr? K = CXCursor_DeclRefExpr; -- 2.40.0