]> granicus.if.org Git - clang/commitdiff
Teach template template argument pack expansions to keep track of the
authorDouglas Gregor <dgregor@apple.com>
Fri, 14 Jan 2011 23:41:42 +0000 (23:41 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 14 Jan 2011 23:41:42 +0000 (23:41 +0000)
number of expansions, when we know it, and propagate that information
through Sema.

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

include/clang/AST/TemplateBase.h
lib/AST/ASTContext.cpp
lib/AST/ASTImporter.cpp
lib/AST/DeclTemplate.cpp
lib/AST/TemplateBase.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp

index 93ec35bebe689a839382896fe09d26276b397ba6..a4e074e083f624919f31762420a39ad4e74e4425 100644 (file)
@@ -80,8 +80,14 @@ private:
       const TemplateArgument *Args;
       unsigned NumArgs;
     } Args;
+    struct {
+      void *Name;
+      unsigned NumExpansions;
+    } TemplateArg;
   };
 
+  TemplateArgument(TemplateName, bool); // DO NOT USE
+  
 public:
   /// \brief Construct an empty, invalid template argument.
   TemplateArgument() : Kind(Null), TypeOrValue(0) { }
@@ -107,8 +113,7 @@ public:
     Integer.Type = Type.getAsOpaquePtr();
   }
 
-  /// \brief Construct a template argument that is a template or a pack
-  /// expansion of templates.
+  /// \brief Construct a template argument that is a template.
   ///
   /// This form of template argument is generally used for template template
   /// parameters. However, the template name could be a dependent template
@@ -116,13 +121,33 @@ public:
   /// is taken.
   ///
   /// \param Name The template name.
-  /// \param PackExpansion Whether this template argument is a pack expansion.
-  TemplateArgument(TemplateName Name, bool PackExpansion = false) 
-    : Kind(PackExpansion? TemplateExpansion : Template) 
+  TemplateArgument(TemplateName Name) : Kind(Template) 
   {
-    TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer());
+    TemplateArg.Name = Name.getAsVoidPointer();
+    TemplateArg.NumExpansions = 0;
   }
-  
+
+  /// \brief Construct a template argument that is a template pack expansion.
+  ///
+  /// 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.
+  ///
+  /// \param Name The template name.
+  ///
+  /// \param NumExpansions The number of expansions that will be generated by
+  /// instantiating
+  TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions)
+    : Kind(TemplateExpansion) 
+  {
+    TemplateArg.Name = Name.getAsVoidPointer();
+    if (NumExpansions)
+      TemplateArg.NumExpansions = *NumExpansions + 1;
+    else
+      TemplateArg.NumExpansions = 0;
+  }
+
   /// \brief Construct a template argument that is an expression.
   ///
   /// This form of template argument only occurs in template argument
@@ -151,6 +176,9 @@ public:
     } else if (Kind == Pack) {
       Args.NumArgs = Other.Args.NumArgs;
       Args.Args = Other.Args.Args;
+    } else if (Kind == Template || Kind == TemplateExpansion) {
+      TemplateArg.Name = Other.TemplateArg.Name;
+      TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
     } else
       TypeOrValue = Other.TypeOrValue;
   }
@@ -177,6 +205,9 @@ public:
     } else if (Other.Kind == Pack) {
       Args.NumArgs = Other.Args.NumArgs;
       Args.Args = Other.Args.Args;
+    } else if (Kind == Template || Kind == TemplateExpansion) {
+      TemplateArg.Name = Other.TemplateArg.Name;
+      TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
     } else {
       TypeOrValue = Other.TypeOrValue;
     }
@@ -234,8 +265,7 @@ public:
     if (Kind != Template)
       return TemplateName();
     
-    return TemplateName::getFromVoidPointer(
-                                          reinterpret_cast<void*>(TypeOrValue));
+    return TemplateName::getFromVoidPointer(TemplateArg.Name);
   }
 
   /// \brief Retrieve the template argument as a template name; if the argument
@@ -244,10 +274,13 @@ public:
     if (Kind != Template && Kind != TemplateExpansion)
       return TemplateName();
     
-    return TemplateName::getFromVoidPointer(
-                                          reinterpret_cast<void*>(TypeOrValue));
+    return TemplateName::getFromVoidPointer(TemplateArg.Name);
   }
 
+  /// \brief Retrieve the number of expansions that a template template argument
+  /// expansion will produce, if known.
+  llvm::Optional<unsigned> getNumTemplateExpansions() const;
+  
   /// \brief Retrieve the template argument as an integral value.
   llvm::APSInt *getAsIntegral() {
     if (Kind != Integral)
index a98e0636d493896518dbfae1eec8e34ef95741bb..e1e6fd08aa20998372d4d382e1b772d80dacec2e 100644 (file)
@@ -2768,7 +2768,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
     case TemplateArgument::TemplateExpansion:
       return TemplateArgument(getCanonicalTemplateName(
                                          Arg.getAsTemplateOrTemplatePattern()),
-                              true);
+                              Arg.getNumTemplateExpansions());
 
     case TemplateArgument::Integral:
       return TemplateArgument(*Arg.getAsIntegral(),
index 7989b9f278b2e7bc40b6df7063b244278f859bb5..f9fe18f5dfb7a967c302c65b852dab9341709fa8 100644 (file)
@@ -1823,7 +1823,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
     if (ToTemplate.isNull())
       return TemplateArgument();
     
-    return TemplateArgument(ToTemplate, true);
+    return TemplateArgument(ToTemplate, From.getNumTemplateExpansions());
   }
 
   case TemplateArgument::Expression:
index e7902e996a95459ca902d0d25a0a1eaaf196967b..b6716b34bdf43e76eab0e85057378c2cecbaca1e 100644 (file)
@@ -337,7 +337,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
       Arg = TemplateArgument(E);
     } else {
       TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
-      Arg = TemplateArgument(TemplateName(TTP), TTP->isParameterPack());
+      if (TTP->isParameterPack())
+        Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+      else
+        Arg = TemplateArgument(TemplateName(TTP));
     }
     
     if ((*Param)->isTemplateParameterPack())
index 26c0c089718af882e6d64f7c06cc36870337723b..f3def3eff2cf0156c1791e1899568bb9e7734ff0 100644 (file)
@@ -135,6 +135,14 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
   return false;
 }
 
+llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+  assert(Kind == TemplateExpansion);
+  if (TemplateArg.NumExpansions)
+    return TemplateArg.NumExpansions - 1;
+  
+  return llvm::Optional<unsigned>();
+}
+
 void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
                                const ASTContext &Context) const {
   ID.AddInteger(Kind);
@@ -223,7 +231,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
     return cast<PackExpansionExpr>(getAsExpr())->getPattern();
     
   case TemplateExpansion:
-    return TemplateArgument(getAsTemplateOrTemplatePattern(), false);
+    return TemplateArgument(getAsTemplateOrTemplatePattern());
     
   case Declaration:
   case Integral:
@@ -389,8 +397,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
   }
 
   case TemplateArgument::TemplateExpansion:
-    // FIXME: Variadic templates num expansions
     Ellipsis = getTemplateEllipsisLoc();
+    NumExpansions = Argument.getNumTemplateExpansions();
     return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
                                getTemplateQualifierRange(),
                                getTemplateNameLoc());
index 5101b3b525865e98a4a745dd8f1c37715457533a..3c9d386f81afd4ae0989800456e2b4b12b65b6d3 100644 (file)
@@ -467,8 +467,12 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
     
   case ParsedTemplateArgument::Template: {
     TemplateName Template = Arg.getAsTemplate().get();
-    return TemplateArgumentLoc(TemplateArgument(Template,
-                                                Arg.getEllipsisLoc().isValid()),
+    TemplateArgument TArg;
+    if (Arg.getEllipsisLoc().isValid())
+      TArg = TemplateArgument(Template, llvm::Optional<unsigned int>());
+    else
+      TArg = Template;
+    return TemplateArgumentLoc(TArg,
                                Arg.getScopeSpec().getRange(),
                                Arg.getLocation(),
                                Arg.getEllipsisLoc());
index 13cc17ef536a9e89d0987e1e7b7eda50e18544f6..17b38bc1de6140322ffa58c1a90d43bad64b06f6 100644 (file)
@@ -809,11 +809,8 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
         assert(Arg.getKind() == TemplateArgument::Pack && 
                "Missing argument pack");
         
-        if (getSema().ArgumentPackSubstitutionIndex == -1) {
-          // FIXME: Variadic templates fun case.
-          getSema().Diag(Loc, diag::err_pack_expansion_mismatch_unsupported);
+        if (getSema().ArgumentPackSubstitutionIndex == -1)
           return 0;
-        }
         
         assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
         Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
index 4abcb88fc017ca81b6b2f938fec0d90f0baa083c..02c95bdb13ced89b685552817ec5c75581c6ac39 100644 (file)
@@ -2188,7 +2188,7 @@ public:
     case TemplateArgument::Template:
       return TemplateArgumentLoc(TemplateArgument(
                                           Pattern.getArgument().getAsTemplate(),
-                                                  true),
+                                                  NumExpansions),
                                  Pattern.getTemplateQualifierRange(),
                                  Pattern.getTemplateNameLoc(),
                                  EllipsisLoc);
index 2c52f7f3a0c76e93e348988d8b14d9f7ca996056..c6ecdea410a3c53768b223911f206e1fb07fa37d 100644 (file)
@@ -4290,9 +4290,13 @@ ASTReader::ReadTemplateArgument(PerFileData &F,
     return TemplateArgument(Value, T);
   }
   case TemplateArgument::Template: 
+    return TemplateArgument(ReadTemplateName(Record, Idx));
   case TemplateArgument::TemplateExpansion: {
     TemplateName Name = ReadTemplateName(Record, Idx);
-    return TemplateArgument(Name, Kind == TemplateArgument::TemplateExpansion);
+    llvm::Optional<unsigned> NumTemplateExpansions;
+    if (unsigned NumExpansions = Record[Idx++])
+      NumTemplateExpansions = NumExpansions - 1;
+    return TemplateArgument(Name, NumTemplateExpansions);
   }
   case TemplateArgument::Expression:
     return TemplateArgument(ReadExpr(F));
index 00d46bc66030898dcabef2309d69ef1fbf3a481e..54a2648cd3c7fa9ca66a7afbd32e88418d012243 100644 (file)
@@ -3231,8 +3231,14 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
     AddTypeRef(Arg.getIntegralType(), Record);
     break;
   case TemplateArgument::Template:
+    AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+    break;
   case TemplateArgument::TemplateExpansion:
     AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+    if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+      Record.push_back(*NumExpansions + 1);
+    else
+      Record.push_back(0);
     break;
   case TemplateArgument::Expression:
     AddStmt(Arg.getAsExpr());
index 64554ab63406ccc5394644a40d12aa45d0f198d0..5ce5e63adb37295bcc39304a1c2195909669c1df 100644 (file)
@@ -88,4 +88,42 @@ namespace PacksAtDifferentLevels {
                                        pair<int, unsigned int>,
                                        pair<long, unsigned long>)
                                      >::value == 1? 1 : -1]; 
+
+  template<typename T, typename U>
+  struct some_function_object {
+    template<typename>
+    struct result_of;
+  };
+
+  template<template<class> class...> struct metafun_tuple { };
+
+  template<typename ...Types1>
+  struct X3 {
+    template<typename, typename> struct Inner {
+      static const unsigned value = 0;
+    };
+
+    template<typename ...Types2>
+    struct Inner<tuple<pair<Types1, Types2>...>,
+                 metafun_tuple<some_function_object<Types1, Types2>::template result_of...> > {
+      static const unsigned value = 1;
+    };
+  };
+
+  int check6[X3<short, int, long>::Inner<tuple<pair<short, unsigned short>,
+                                               pair<int, unsigned int>,
+                                               pair<long, unsigned long>>,
+                                 metafun_tuple<
+                         some_function_object<short, unsigned short>::result_of,
+                         some_function_object<int, unsigned int>::result_of,
+                         some_function_object<long, unsigned long>::result_of>
+                                     >::value == 1? 1 : -1];
+  int check7[X3<short, int>::Inner<tuple<pair<short, unsigned short>,
+                                               pair<int, unsigned int>,
+                                               pair<long, unsigned long>>,
+                                 metafun_tuple<
+                         some_function_object<short, unsigned short>::result_of,
+                         some_function_object<int, unsigned int>::result_of,
+                         some_function_object<long, unsigned long>::result_of>
+                                     >::value == 0? 1 : -1];
 }