]> granicus.if.org Git - clang/commitdiff
Add semantic analysis for the creation of and an AST representation
authorDouglas Gregor <dgregor@apple.com>
Wed, 5 Jan 2011 17:40:24 +0000 (17:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 5 Jan 2011 17:40:24 +0000 (17:40 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122890 91177308-0d34-0410-b5e6-96231b3b80d8

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

index c7cb2fbe8e906b97cd793c508bf7b69ca7414a99..758926c957971127c8343bfd569ae4aaf9165448 100644 (file)
@@ -77,6 +77,10 @@ private:
       TemplateArgument *Args;
       unsigned NumArgs;
     } Args;
+    struct {
+      void *Template;
+      bool PackExpansion;
+    } TemplateArg;
   };
 
 public:
@@ -104,14 +108,21 @@ public:
     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 @@ public:
     } 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 @@ public:
     } 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 @@ public:
     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 @@ private:
     struct {
       unsigned QualifierRange[2];
       unsigned TemplateNameLoc;
+      unsigned EllipsisLoc;
     } Template;
   };
 
@@ -318,11 +332,13 @@ public:
   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 @@ public:
   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 @@ public:
 
   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 @@ public:
     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.
   ///
index 6a60ab1294d8152ab72539994ea5f29ac34da5af..5aa6f47425aa2ddf373b20b4861431256fa92339 100644 (file)
@@ -58,7 +58,7 @@ namespace clang {
                            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 @@ namespace clang {
       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 @@ namespace clang {
     /// \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
index 2755a9e23021b1cfebf1e85824afaed20bd5257b..b7a586cb17e55ae9c34bc2a2817dc17104157fd6 100644 (file)
@@ -335,8 +335,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
       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()) {
index c9715199612b0d1670c10c5350c74d8bb9a4da22..6eae6a4192f8b7477743c36708d859543f2d4302 100644 (file)
@@ -76,8 +76,7 @@ bool TemplateArgument::isPackExpansion() const {
     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 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
     break;
 
   case Template:
-    if (getAsTemplate().containsUnexpandedParameterPack())
+    if (!TemplateArg.PackExpansion && 
+        getAsTemplate().containsUnexpandedParameterPack())
       return true;
     break;
         
@@ -135,12 +135,14 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
     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 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
   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 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
   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 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
     
   case Template: {
     getAsTemplate().print(Out, Policy);
+    if (TemplateArg.PackExpansion)
+      Out << "...";
     break;
   }
     
@@ -254,12 +260,9 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
     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 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
     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 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
   }
       
   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 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
     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
index ff0fe9d6b6bd70ad80b91fd49b175d4a89238953..9adcf1c81fd84fa2b10e7cedb614162edcec3915 100644 (file)
@@ -437,6 +437,17 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) {
   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 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
     
   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());
   }
   }
   
index 18bfee301ba23186aa4d93964d11429ccaf099e8..a72a29378a8199c530b31ba5b7f41573870d064b 100644 (file)
@@ -1344,19 +1344,20 @@ getTrivialTemplateArgumentLoc(Sema &S,
     
   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());
index acb73144d9217b5f856c43059d68ebc6e6c3e96b..fb88bd114b4f65735fccdf155ee1bb7d9169b6d2 100644 (file)
@@ -130,6 +130,22 @@ namespace {
 
       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 @@ Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
   }
     
   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();
index f3320a041583c492e64160a73e8c2473d867517d..ed0e58f18fa90cb2e17e8aab58a3b1a0a5ffc3ae 100644 (file)
@@ -3381,7 +3381,9 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F,
   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 @@ ASTReader::ReadTemplateArgument(PerFileData &F,
     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: {
index cbf5ac79192bac9957b75dc1c0b607df988c0968..44f17e40b1a31c3ffad36ef809b444c19ae28845 100644 (file)
@@ -2889,6 +2889,7 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
   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 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
     break;
   case TemplateArgument::Template:
     AddTemplateName(Arg.getAsTemplate(), Record);
+    Record.push_back(Arg.isPackExpansion());
     break;
   case TemplateArgument::Expression:
     AddStmt(Arg.getAsExpr());
index 00f56ab86d055ca9cf398b430019aeb081d105f5..d31a1f05fe8302093b844641d19c8a7b84f026aa 100644 (file)
@@ -34,10 +34,9 @@ template<typename ...Types, typename T> struct X1t<T, Types...> { };
 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 @@ void f1t(X1t<T, Types...>);
 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...>);