]> granicus.if.org Git - clang/commitdiff
Introduce a new expression kind, SubstNonTypeTemplateParmPackExpr,
authorDouglas Gregor <dgregor@apple.com>
Sat, 15 Jan 2011 01:15:58 +0000 (01:15 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 15 Jan 2011 01:15:58 +0000 (01:15 +0000)
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

18 files changed:
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/StmtNodes.td
include/clang/Serialization/ASTBitCodes.h
lib/AST/ExprCXX.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Checkers/ExprEngine.cpp
test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index abc8c77a38f8b2f99a4b8afa24bdba2f0d4bab0a..f6bbfbf361bec9c076d23830888e40be58c5e5ab 100644 (file)
@@ -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
 
index 3d1279b2527c0f099c9a77c257235b05b6e535fc..532759b03329bce326ba5826138fdf17d802c88f 100644 (file)
@@ -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, { })
index 9322db12c59a4bff3b0a578cd88131c0d04d811a..58db87b4c24b5728c82aba175087855c5bbb648e 100644 (file)
@@ -113,6 +113,7 @@ def UnresolvedMemberExpr : DStmt<OverloadExpr>;
 def CXXNoexceptExpr : DStmt<Expr>;
 def PackExpansionExpr : DStmt<Expr>;
 def SizeOfPackExpr : DStmt<Expr>;
+def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
index 6ef4dbeb0cb650f783845527ee34c07c09879142..7a9019f384b8bdfd088e23e544470f6b1853d64e 100644 (file)
@@ -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
index 0426e59a74d837373fb5c2a459f353fa75c5b24c..2c790bd2731e51c7715e1bc47c6419ef20d07c86 100644 (file)
@@ -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();
+}
+
+
index a9ebe6fdb3cf963962ad33ce0a61934cf5641a89..c9f4fa8daa2555cd01c64b0e4f5c361057ec1490 100644 (file)
@@ -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.
index 57ceb3f48185d96391ae819d7d837e241b1b5220..cb7381016369fa8e553cd19e5d3491df477230ee 100644 (file)
@@ -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:
index 0ebd7da679c2c30142dec0e640637953a3cf7546..2f8be294f2c56fa58256d90436beaff8e88ad851 100644 (file)
@@ -1948,6 +1948,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
     break;
   }
 
+  case Expr::SubstNonTypeTemplateParmPackExprClass:
+    mangleTemplateParameter(
+     cast<SubstNonTypeTemplateParmPackExpr>(E)->getParameterPack()->getIndex());
+    break;
+      
   case Expr::DependentScopeDeclRefExprClass: {
     const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
     NestedNameSpecifier *NNS = DRE->getQualifier();
index 2c8504357ef0d031ffcb9d78522d7f9de3941c9f..4c18a526bbf6852db07078daa51f2387ca175e6e 100644 (file)
@@ -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) {
index 232f48e1eeef51eb150a4065a96799ceb6fff071..e75c274015c0e5f096125b40ce1df0e0fce052f1 100644 (file)
@@ -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);  
 }
index 17b38bc1de6140322ffa58c1a90d43bad64b06f6..8943daa36983c2f4790dbf9ca8e3fc6662010ab5 100644 (file)
@@ -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<ValueDecl>(Arg.getAsDecl());
+    
+    // Find the instantiation of the template argument.  This is
+    // required for nested templates.
+    VD = cast_or_null<ValueDecl>(
+                   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) {
index 02c95bdb13ced89b685552817ec5c75581c6ac39..73982a71c28218356d7f275eb2f7068a8e797f7b 100644 (file)
@@ -6892,6 +6892,14 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
                                             *NumExpansions);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
+                                          SubstNonTypeTemplateParmPackExpr *E) {
+  // Default behavior is to do nothing with this transformation.
+  return SemaRef.Owned(E);
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
index 022b6194120a8bcc5398012fffb24d06f775b12b..5fec238ab8dd0ef196ff95f52ffa323a3308cdc1 100644 (file)
@@ -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<NamedDecl>(Reader.GetDecl(Record[Idx++]));
 }
 
+void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
+                                          SubstNonTypeTemplateParmPackExpr *E) {
+  VisitExpr(E);
+  E->Param
+    = cast_or_null<NonTypeTemplateParmDecl>(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;
index 205f4dc2a964f2394abe385594340348a3cef206..e03a780fad7c5c268f923b74258fb7808402b6e7 100644 (file)
@@ -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;
index f3c305a388007190ad86cf965c72d0a50d9f328e..f45041b73e9c00844ecb098d099b4c75c83fa094 100644 (file)
@@ -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<bool> OldSink(Builder->BuildSinks);
       Builder->BuildSinks = true;
index 5ce5e63adb37295bcc39304a1c2195909669c1df..01d5759188a8e20bc01f1a0128ee4b2f750cd8f5 100644 (file)
@@ -126,4 +126,27 @@ namespace PacksAtDifferentLevels {
                          some_function_object<int, unsigned int>::result_of,
                          some_function_object<long, unsigned long>::result_of>
                                      >::value == 0? 1 : -1];
+
+  template<unsigned I, unsigned J> struct unsigned_pair { };
+
+  template<unsigned ...Values1>
+  struct X4 {
+    template<typename> struct Inner {
+      static const unsigned value = 0;
+    };
+
+    template<unsigned ...Values2>
+    struct Inner<tuple<unsigned_pair<Values1, Values2>...>> {
+      static const unsigned value = 1;
+    };
+  };
+
+  int check8[X4<1, 3, 5>::Inner<tuple<unsigned_pair<1, 2>,
+                                      unsigned_pair<3, 4>,
+                                      unsigned_pair<5, 6>>
+                                >::value == 1? 1 : -1];
+  int check9[X4<1, 3>::Inner<tuple<unsigned_pair<1, 2>,
+                                   unsigned_pair<3, 4>,
+                                   unsigned_pair<5, 6>>
+                             >::value == 0? 1 : -1];
 }
index 38b86cd23fa1f219b94a67555960c28c00ba29e3..574b4c8b4efb016a6d2877b1f424a4516fb306f1 100644 (file)
@@ -2649,6 +2649,9 @@ static Decl *getDeclFromExpr(Stmt *E) {
 
   if (ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E))
     return PE->getProtocol();
+  if (SubstNonTypeTemplateParmPackExpr *NTTP 
+                              = dyn_cast<SubstNonTypeTemplateParmPackExpr>(E))
+    return NTTP->getParameterPack();
   
   return 0;
 }
index 1a75284de389ca2e698e0d90d8011d9a5cf12e71..7bcd1597baf2dd555dd0f268fc5e29fd0acc4f4f 100644 (file)
@@ -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;