[cfe-commits] r122890 - in /cfe/trunk: include/clang/AST/TemplateBase.h include/clang/Sema/ParsedTemplate.h lib/AST/DeclTemplate.cpp lib/AST/TemplateBase.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/temp/temp.param/p11-0x.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 5 09:40:25 PST 2011


Author: dgregor
Date: Wed Jan  5 11:40:24 2011
New Revision: 122890

URL: http://llvm.org/viewvc/llvm-project?rev=122890&view=rev
Log:
Add semantic analysis for the creation of and an AST representation
for template template argument pack expansions. This allows fun such
as: 

  template<template<class> class ...> struct apply_impl { /*...*/ };
  template<template<class> class ...Metafunctions> struct apply {
    typedef typename apply_impl<Metafunctions...>::type type;
  };

However, neither template argument deduction nor template
instantiation is implemented for template template argument packs, so
this functionality isn't useful yet.

I'll probably replace the encoding of template template
argument pack expansions in TemplateArgument so that it's harder to
accidentally forget about the expansion. However, this is a step in
the right general direction.

Modified:
    cfe/trunk/include/clang/AST/TemplateBase.h
    cfe/trunk/include/clang/Sema/ParsedTemplate.h
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/AST/TemplateBase.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/temp/temp.param/p11-0x.cpp

Modified: cfe/trunk/include/clang/AST/TemplateBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateBase.h?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateBase.h (original)
+++ cfe/trunk/include/clang/AST/TemplateBase.h Wed Jan  5 11:40:24 2011
@@ -77,6 +77,10 @@
       TemplateArgument *Args;
       unsigned NumArgs;
     } Args;
+    struct {
+      void *Template;
+      bool PackExpansion;
+    } TemplateArg;
   };
 
 public:
@@ -104,14 +108,21 @@
     Integer.Type = Type.getAsOpaquePtr();
   }
 
-  /// \brief Construct a template argument that is a template.
+  /// \brief Construct a template argument that is a template or a pack
+  /// expansion of templates.
   ///
   /// This form of template argument is generally used for template template
   /// parameters. However, the template name could be a dependent template
   /// name that ends up being instantiated to a function template whose address
   /// is taken.
-  TemplateArgument(TemplateName Name) : Kind(Template) {
-    TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer());
+  ///
+  /// \param Name The template name.
+  /// \param PackExpansion Whether this template argument is a pack expansion.
+  TemplateArgument(TemplateName Name, bool PackExpansion = false) 
+    : Kind(Template) 
+  {
+    TemplateArg.Template = Name.getAsVoidPointer();
+    TemplateArg.PackExpansion = PackExpansion;
   }
   
   /// \brief Construct a template argument that is an expression.
@@ -142,8 +153,9 @@
     } else if (Kind == Pack) {
       Args.NumArgs = Other.Args.NumArgs;
       Args.Args = Other.Args.Args;
-    }
-    else
+    } else if (Kind == Template) {
+      TemplateArg = Other.TemplateArg;
+    } else
       TypeOrValue = Other.TypeOrValue;
   }
 
@@ -169,6 +181,8 @@
     } else if (Other.Kind == Pack) {
       Args.NumArgs = Other.Args.NumArgs;
       Args.Args = Other.Args.Args;
+    } else if (Other.Kind == Template) {
+      TemplateArg = Other.TemplateArg;
     } else {
       TypeOrValue = Other.TypeOrValue;
     }
@@ -220,8 +234,7 @@
     if (Kind != Template)
       return TemplateName();
     
-    return TemplateName::getFromVoidPointer(
-                                        reinterpret_cast<void *> (TypeOrValue));
+    return TemplateName::getFromVoidPointer(TemplateArg.Template);
   }
   
   /// \brief Retrieve the template argument as an integral value.
@@ -307,6 +320,7 @@
     struct {
       unsigned QualifierRange[2];
       unsigned TemplateNameLoc;
+      unsigned EllipsisLoc;
     } Template;
   };
 
@@ -318,11 +332,13 @@
   TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
   
   TemplateArgumentLocInfo(SourceRange QualifierRange, 
-                          SourceLocation TemplateNameLoc)
+                          SourceLocation TemplateNameLoc,
+                          SourceLocation EllipsisLoc)
   {
     Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding();
     Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding();
     Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
+    Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
   }
 
   TypeSourceInfo *getAsTypeSourceInfo() const {
@@ -342,6 +358,10 @@
   SourceLocation getTemplateNameLoc() const {
     return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc);
   }
+  
+  SourceLocation getTemplateEllipsisLoc() const {
+    return SourceLocation::getFromRawEncoding(Template.EllipsisLoc);
+  }
 };
 
 /// Location wrapper for a TemplateArgument.  TemplateArgument is to
@@ -370,8 +390,10 @@
 
   TemplateArgumentLoc(const TemplateArgument &Argument, 
                       SourceRange QualifierRange,
-                      SourceLocation TemplateNameLoc)
-    : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) {
+                      SourceLocation TemplateNameLoc,
+                      SourceLocation EllipsisLoc = SourceLocation())
+    : Argument(Argument), 
+      LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) {
     assert(Argument.getKind() == TemplateArgument::Template);
   }
   
@@ -419,6 +441,11 @@
     return LocInfo.getTemplateNameLoc();
   }  
   
+  SourceLocation getTemplateEllipsisLoc() const {
+    assert(Argument.getKind() == TemplateArgument::Template);
+    return LocInfo.getTemplateEllipsisLoc();
+  }
+  
   /// \brief When the template argument is a pack expansion, returns 
   /// the pattern of the pack expansion.
   ///

Modified: cfe/trunk/include/clang/Sema/ParsedTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ParsedTemplate.h?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ParsedTemplate.h (original)
+++ cfe/trunk/include/clang/Sema/ParsedTemplate.h Wed Jan  5 11:40:24 2011
@@ -58,7 +58,7 @@
                            SourceLocation TemplateLoc) 
       : Kind(ParsedTemplateArgument::Template),
         Arg(Template.getAsOpaquePtr()), 
-        Loc(TemplateLoc), SS(SS) { }
+        Loc(TemplateLoc), SS(SS), EllipsisLoc() { }
     
     /// \brief Determine whether the given template argument is invalid.
     bool isInvalid() const { return Arg == 0; }
@@ -95,6 +95,21 @@
       return SS;
     }
     
+    /// \brief Retrieve the location of the ellipsis that makes a template
+    /// template argument into a pack expansion.
+    SourceLocation getEllipsisLoc() const {
+      assert(Kind == Template && 
+             "Only template template arguments can have an ellipsis");
+      return EllipsisLoc;
+    }
+    
+    /// \brief Retrieve a pack expansion of the given template template
+    /// argument.
+    ///
+    /// \param EllipsisLoc The location of the ellipsis.
+    ParsedTemplateArgument getTemplatePackExpansion(
+                                              SourceLocation EllipsisLoc) const;
+    
   private:
     KindType Kind;
     
@@ -109,6 +124,10 @@
     /// \brief The nested-name-specifier that can accompany a template template
     /// argument.
     CXXScopeSpec SS;
+    
+    /// \brief The ellipsis location that can accompany a template template
+    /// argument (turning it into a template template argument expansion).
+    SourceLocation EllipsisLoc;
   };
   
   /// \brief Information about a template-id annotation

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed Jan  5 11:40:24 2011
@@ -335,8 +335,7 @@
       Arg = TemplateArgument(E);
     } else {
       TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
-      // FIXME: Variadic templates.
-      Arg = TemplateArgument(TemplateName(TTP));
+      Arg = TemplateArgument(TemplateName(TTP), TTP->isParameterPack());
     }
     
     if ((*Param)->isTemplateParameterPack()) {

Modified: cfe/trunk/lib/AST/TemplateBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateBase.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TemplateBase.cpp (original)
+++ cfe/trunk/lib/AST/TemplateBase.cpp Wed Jan  5 11:40:24 2011
@@ -76,8 +76,7 @@
     return isa<PackExpansionType>(getAsType());
       
   case Template:
-    // FIXME: Template template pack expansions.
-    break;
+    return TemplateArg.PackExpansion;
     
   case Expression:
     return isa<PackExpansionExpr>(getAsExpr());
@@ -99,7 +98,8 @@
     break;
 
   case Template:
-    if (getAsTemplate().containsUnexpandedParameterPack())
+    if (!TemplateArg.PackExpansion && 
+        getAsTemplate().containsUnexpandedParameterPack())
       return true;
     break;
         
@@ -135,12 +135,14 @@
     break;
 
   case Template:
+    ID.AddBoolean(TemplateArg.PackExpansion);
     if (TemplateTemplateParmDecl *TTP
           = dyn_cast_or_null<TemplateTemplateParmDecl>(
                                        getAsTemplate().getAsTemplateDecl())) {
       ID.AddBoolean(true);
       ID.AddInteger(TTP->getDepth());
       ID.AddInteger(TTP->getPosition());
+      ID.AddBoolean(TTP->isParameterPack());
     } else {
       ID.AddBoolean(false);
       ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
@@ -171,10 +173,13 @@
   case Null:
   case Type:
   case Declaration:
-  case Template:
   case Expression:
     return TypeOrValue == Other.TypeOrValue;
 
+  case Template:
+    return TemplateArg.Template == Other.TemplateArg.Template &&
+           TemplateArg.PackExpansion == Other.TemplateArg.PackExpansion;
+      
   case Integral:
     return getIntegralType() == Other.getIntegralType() &&
            *getAsIntegral() == *Other.getAsIntegral();
@@ -195,21 +200,20 @@
   assert(isPackExpansion());
   
   switch (getKind()) {
-    case Type:
-      return getAsType()->getAs<PackExpansionType>()->getPattern();
-      
-    case Expression:
-      return cast<PackExpansionExpr>(getAsExpr())->getPattern();
-      
-    case Template:
-      // FIXME: Variadic templates.
-      llvm_unreachable("Template pack expansions unsupported");
-      
-    case Declaration:
-    case Integral:
-    case Pack:
-    case Null:
-      return TemplateArgument();
+  case Type:
+    return getAsType()->getAs<PackExpansionType>()->getPattern();
+    
+  case Expression:
+    return cast<PackExpansionExpr>(getAsExpr())->getPattern();
+    
+  case Template:
+    return TemplateArgument(getAsTemplate(), false);
+    
+  case Declaration:
+  case Integral:
+  case Pack:
+  case Null:
+    return TemplateArgument();
   }
   
   return TemplateArgument();
@@ -246,6 +250,8 @@
     
   case Template: {
     getAsTemplate().print(Out, Policy);
+    if (TemplateArg.PackExpansion)
+      Out << "...";
     break;
   }
     
@@ -254,12 +260,9 @@
     break;
   }
     
-  case Expression: {
-    // FIXME: This is non-optimal, since we're regurgitating the
-    // expression we were given.
+  case Expression:
     getAsExpr()->printPretty(Out, 0, Policy);
     break;
-  }
     
   case Pack:
     Out << "<";
@@ -296,12 +299,15 @@
     else
       return SourceRange();
 
-  case TemplateArgument::Template:
+  case TemplateArgument::Template: {
+    SourceLocation End = getTemplateNameLoc();
+    if (getTemplateEllipsisLoc().isValid())
+      End = getTemplateEllipsisLoc();
     if (getTemplateQualifierRange().isValid())
-      return SourceRange(getTemplateQualifierRange().getBegin(),
-                         getTemplateNameLoc());
-    return SourceRange(getTemplateNameLoc());
-
+      return SourceRange(getTemplateQualifierRange().getBegin(), End);
+    return SourceRange(getTemplateNameLoc(), End);
+  }
+      
   case TemplateArgument::Integral:
   case TemplateArgument::Pack:
   case TemplateArgument::Null:
@@ -351,8 +357,9 @@
   }
       
   case TemplateArgument::Template:
-    // FIXME: Variadic templates.
-      llvm_unreachable("Template pack expansions unsupported");
+    return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
+                               getTemplateQualifierRange(),
+                               getTemplateNameLoc());
     
   case TemplateArgument::Declaration:
   case TemplateArgument::Integral:
@@ -382,7 +389,10 @@
     return DB << Arg.getAsIntegral()->toString(10);
       
   case TemplateArgument::Template:
-    return DB << Arg.getAsTemplate();
+    DB << Arg.getAsTemplate();
+    if (Arg.isPackExpansion())
+      DB << "...";
+    return DB;
       
   case TemplateArgument::Expression: {
     // This shouldn't actually ever happen, so it's okay that we're

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan  5 11:40:24 2011
@@ -437,6 +437,17 @@
   return 0;
 }
 
+ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion(
+                                             SourceLocation EllipsisLoc) const {
+  assert(Kind == Template && 
+         "Only template template arguments can be pack expansions here");
+  assert(getAsTemplate().get().containsUnexpandedParameterPack() &&
+         "Template template argument pack expansion without packs");
+  ParsedTemplateArgument Result(*this);
+  Result.EllipsisLoc = EllipsisLoc;
+  return Result;
+}
+
 static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
                                             const ParsedTemplateArgument &Arg) {
   
@@ -456,9 +467,11 @@
     
   case ParsedTemplateArgument::Template: {
     TemplateName Template = Arg.getAsTemplate().get();
-    return TemplateArgumentLoc(TemplateArgument(Template),
+    return TemplateArgumentLoc(TemplateArgument(Template,
+                                                Arg.getEllipsisLoc().isValid()),
                                Arg.getScopeSpec().getRange(),
-                               Arg.getLocation());
+                               Arg.getLocation(),
+                               Arg.getEllipsisLoc());
   }
   }
   

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jan  5 11:40:24 2011
@@ -1344,19 +1344,20 @@
     
   case TemplateArgument::Declaration: {
     Expr *E
-    = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+      = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
     .takeAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(E), E);
   }
     
   case TemplateArgument::Integral: {
     Expr *E
-    = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+      = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(E), E);
   }
     
   case TemplateArgument::Template:
-    return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+    return TemplateArgumentLoc(Arg, SourceRange(), Loc,
+                               Arg.isPackExpansion()? Loc : SourceLocation());
     
   case TemplateArgument::Expression:
     return TemplateArgumentLoc(Arg, Arg.getAsExpr());

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Wed Jan  5 11:40:24 2011
@@ -130,6 +130,22 @@
 
       return true; 
     }
+
+    /// \brief Suppress traversal of template argument pack expansions.
+    bool TraverseTemplateArgument(const TemplateArgument &Arg) {
+      if (Arg.isPackExpansion())
+        return true;
+
+      return inherited::TraverseTemplateArgument(Arg);
+    }
+
+    /// \brief Suppress traversal of template argument pack expansions.
+    bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+      if (ArgLoc.getArgument().isPackExpansion())
+        return true;
+      
+      return inherited::TraverseTemplateArgumentLoc(ArgLoc);
+    }
   };
 }
 
@@ -335,8 +351,16 @@
   }
     
   case ParsedTemplateArgument::Template:
-    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported);
-    return ParsedTemplateArgument();
+    if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) {
+      SourceRange R(Arg.getLocation());
+      if (Arg.getScopeSpec().isValid())
+        R.setBegin(Arg.getScopeSpec().getBeginLoc());
+      Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+        << R;
+      return ParsedTemplateArgument();
+    }
+      
+    return Arg.getTemplatePackExpansion(EllipsisLoc);
   }
   llvm_unreachable("Unhandled template argument kind?");
   return ParsedTemplateArgument();

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Jan  5 11:40:24 2011
@@ -3381,7 +3381,9 @@
   case TemplateArgument::Template: {
     SourceRange QualifierRange = ReadSourceRange(F, Record, Index);
     SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
-    return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc);
+    SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
+    return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc, 
+                                   EllipsisLoc);
   }
   case TemplateArgument::Null:
   case TemplateArgument::Integral:
@@ -4226,8 +4228,11 @@
     QualType T = GetType(Record[Idx++]);
     return TemplateArgument(Value, T);
   }
-  case TemplateArgument::Template:
-    return TemplateArgument(ReadTemplateName(Record, Idx));
+  case TemplateArgument::Template: {
+    TemplateName Name = ReadTemplateName(Record, Idx);
+    bool IsPackExpansion = Record[Idx++];
+    return TemplateArgument(Name, IsPackExpansion);
+  }
   case TemplateArgument::Expression:
     return TemplateArgument(ReadExpr(F));
   case TemplateArgument::Pack: {

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Jan  5 11:40:24 2011
@@ -2889,6 +2889,7 @@
   case TemplateArgument::Template:
     AddSourceRange(Arg.getTemplateQualifierRange(), Record);
     AddSourceLocation(Arg.getTemplateNameLoc(), Record);
+    AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record);
     break;
   case TemplateArgument::Null:
   case TemplateArgument::Integral:
@@ -3176,6 +3177,7 @@
     break;
   case TemplateArgument::Template:
     AddTemplateName(Arg.getAsTemplate(), Record);
+    Record.push_back(Arg.isPackExpansion());
     break;
   case TemplateArgument::Expression:
     AddStmt(Arg.getAsExpr());

Modified: cfe/trunk/test/CXX/temp/temp.param/p11-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p11-0x.cpp?rev=122890&r1=122889&r2=122890&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.param/p11-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.param/p11-0x.cpp Wed Jan  5 11:40:24 2011
@@ -34,10 +34,9 @@
 template<int... Values> struct X1nt;
 template<int ...Values, int V> struct X1nt<V, Values...> { };
 
-// FIXME: Need template template argument packs!
-// template<template<int> class... Meta> struct X1tt;
-// template<template<int> class... Meta, template<int> class M> 
-//  struct X1tt<M, Meta...> { };
+template<template<int> class... Meta> struct X1tt;
+template<template<int> class... Meta, template<int> class M> 
+  struct X1tt<M, Meta...> { };
 
 template<typename ...Types, typename T>
 void f1t(X1t<T, Types...>);
@@ -45,6 +44,5 @@
 template<int ...Values, int V>
 void f1nt(X1nt<V, Values...>);
 
-// FIXME: Need template template argument packs!
-// template<template<int> class... Meta, template<int> class M> 
-// void f1tt(X1tt<M, Meta...>);
+template<template<int> class... Meta, template<int> class M> 
+void f1tt(X1tt<M, Meta...>);





More information about the cfe-commits mailing list