[PATCH] PR12262 - assertion when substituting explicit template arguments does not substitute a sizeof-pack expression.

Serge Pavlov sepavloff at gmail.com
Sun May 26 22:53:08 PDT 2013


sepavloff added you to the CC list for the revision "PR12262 - assertion when substituting explicit template arguments does not substitute a sizeof-pack expression.".

Hi all,

This patch fixes PR12262 - assertion when substituting explicit template arguments does not substitute a sizeof-pack expression. When sizeof...(pack) is used in function declaration, it cannot be calculated until all parameters are deduced from the function arguments. So during substitution of explicit parameters, which takes place before parameter deduction, the pack is represented by its name. However this name isn't present in current scope , this causes assertion failure. As a solution, introduce  parameter pack into the instantiation scope. Similar approach is used when instantiating  template methods.

Please review the fix.

Thank you.

http://llvm-reviews.chandlerc.com/D869

Files:
  include/clang/AST/DeclTemplate.h
  lib/AST/DeclTemplate.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp

Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -948,6 +948,15 @@
   static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, 
                                                   unsigned ID);
 
+  /// \brief Creates a copy of this template type parameter.
+  ///
+  /// \param C AST context in which the new parameter is created.
+  /// \param DC Declaration context of the new parameter.
+  /// \param RelDepth Relative depth of the new parameter.
+  /// \returns Pointer to the created copy.
+  TemplateTypeParmDecl *Clone(const ASTContext &C, DeclContext *DC,
+                              unsigned RelDepth);
+
   /// \brief Whether this template type parameter was declared with
   /// the 'typename' keyword.
   ///
@@ -1068,7 +1077,6 @@
   static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, 
                                                      unsigned ID,
                                                      unsigned NumExpandedTypes);
-    
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::setDepth;
   using TemplateParmPosition::getPosition;
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -468,6 +468,19 @@
                                         0, false);
 }
 
+TemplateTypeParmDecl *
+TemplateTypeParmDecl::Clone(const ASTContext &C, DeclContext *DC,
+                            unsigned RelDepth) {
+  assert(RelDepth <= getDepth());
+  TemplateTypeParmDecl *Result;
+  Result = Create(C, DC, getLocStart(), getLocation(), getDepth() - RelDepth,
+                  getIndex(), getIdentifier(), wasDeclaredWithTypename(),
+                  isParameterPack());
+  if (hasDefaultArgument())
+    Result->setDefaultArgument(getDefaultArgumentInfo(), false);
+  return Result;
+}
+
 SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
   return hasDefaultArgument()
     ? DefaultArgument->getTypeLoc().getBeginLoc()
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3133,6 +3133,36 @@
   LocalInstantiationScope InstScope(*this);
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
+
+  // If function template parameters contain a pack, the latter cannot be
+  // expanded until all parameters are deduced from the function arguments.
+  // If the pack is referenced in the declaration, will be represented by
+  // name. For instance (PR12262):
+  // \code
+  //   template <unsigned N> class array {};
+  //   template<typename T, typename... Types>
+  //   array<sizeof...(Types)> make_array(Types&&... args);
+  //   ...
+  //   auto arr = make_array<int>(1,2,3);
+  // \endcode
+  // In this case when the explicit parameter is substituted, the pack remains
+  // unexpanded.  It should be represented by a named declaration, use the
+  // parameter declaration for this purpose.
+  assert(TemplateParams);
+  for (TemplateParameterList::iterator Param = TemplateParams->begin(),
+                                       ParamEnd = TemplateParams->end();
+       Param != ParamEnd; ++Param) {
+    if (TemplateTypeParmDecl *D = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+      if (D->isParameterPack()) {
+        TemplateTypeParmDecl *Inst = D->Clone(Context, 0, 0);
+        Inst->setAccess(AS_public);
+        // Introduce this template parameter's instantiation into the
+        // instantiation scope.
+        CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+      }
+    }
+  }
+
   SmallVector<DeducedTemplateArgument, 4> Deduced;
   SmallVector<QualType, 4> ParamTypes;
   unsigned NumExplicitlySpecified = 0;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1760,18 +1760,9 @@
   // TODO: don't always clone when decls are refcounted.
   assert(D->getTypeForDecl()->isTemplateTypeParmType());
 
-  TemplateTypeParmDecl *Inst =
-    TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
-                                 D->getLocStart(), D->getLocation(),
-                                 D->getDepth() - TemplateArgs.getNumLevels(),
-                                 D->getIndex(), D->getIdentifier(),
-                                 D->wasDeclaredWithTypename(),
-                                 D->isParameterPack());
+  TemplateTypeParmDecl *Inst = D->Clone(SemaRef.Context, Owner,
+                                        TemplateArgs.getNumLevels());
   Inst->setAccess(AS_public);
-
-  if (D->hasDefaultArgument())
-    Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
-
   // Introduce this template parameter's instantiation into the instantiation
   // scope.
   SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst);
Index: test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
===================================================================
--- /dev/null
+++ test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// PR12262
+
+template<typename T, typename... Ts>
+void abc1(int (*xxx)[sizeof ... (Ts) + 1]);
+
+void qq1 () {
+  abc1<int>(0);
+  abc1<int,double>(0);
+}
+
+
+template <unsigned N> class array {};
+
+
+template<typename T, typename... Types>
+array<sizeof...(Types)> make_array1(Types&&... args);
+
+void qq2 () {
+  array<1> arr = make_array1<int>(1);
+  array<3> arr2 = make_array1<int>(1,array<5>(),0.1);
+}
+
+
+template<typename T, typename... Types>
+int make_array(array<sizeof...(Types)>&, Types... args);
+
+void qq3 () {
+  array<1> a1;
+  int aa1 = make_array<int>(a1,1);
+  array<2> a2;
+  int aa2 = make_array<int>(a2, 0L, "abc");
+}
+
+
+template<typename ... Ts>
+struct AAA {
+  template<typename T, typename... Types>
+  static array<sizeof...(Types)> make_array(Types ... args);
+};
+
+void qq4 () {
+  array<2> arr2 = AAA<int, int>::make_array<int>(1,2);
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D869.1.patch
Type: text/x-patch
Size: 6340 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130526/d2470e81/attachment.bin>


More information about the cfe-commits mailing list