]> granicus.if.org Git - clang/commitdiff
Fix PR11848: decree that an alias template contains an unexpanded parameter pack
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 25 Jan 2012 02:14:59 +0000 (02:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 25 Jan 2012 02:14:59 +0000 (02:14 +0000)
iff its substitution contains an unexpanded parameter pack. This has the effect
that we now reject declarations such as this (which we used to crash when
expanding):

  template<typename T> using Int = int;
  template<typename ...Ts> void f(Int<Ts> ...ints);

The standard is inconsistent on how this case should be treated.

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

lib/AST/Type.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/alias-templates.cpp

index 7b30c500c6e2c7a6e4c232e5163fde55d47d3b8a..b6ce59e977d97605e4d188bfb7ecfaf7216aff01 100644 (file)
@@ -1889,7 +1889,9 @@ TemplateSpecializationType(TemplateName T,
          Canon.isNull()? T.isDependent() : Canon->isDependentType(),
          Canon.isNull()? T.isDependent() 
                        : Canon->isInstantiationDependentType(),
-         false, T.containsUnexpandedParameterPack()),
+         false,
+         Canon.isNull()? T.containsUnexpandedParameterPack()
+                       : Canon->containsUnexpandedParameterPack()),
     Template(T), NumArgs(NumArgs) {
   assert(!T.getAsDependentTemplateName() && 
          "Use DependentTemplateSpecializationType for dependent template-name");
@@ -1922,7 +1924,7 @@ TemplateSpecializationType(TemplateName T,
     if (Args[Arg].getKind() == TemplateArgument::Type &&
         Args[Arg].getAsType()->isVariablyModifiedType())
       setVariablyModified();
-    if (Args[Arg].containsUnexpandedParameterPack())
+    if (Canon.isNull() && Args[Arg].containsUnexpandedParameterPack())
       setContainsUnexpandedParameterPack();
 
     new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
index 2b96a1c7447f02414a2f660aa0198b8714d55e71..e183f1f1c1d7d8cbb8fffd08755eb6122a060c1b 100644 (file)
@@ -1510,7 +1510,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
   // FIXME: When OldParm is a parameter pack and NewParm is not a parameter
   // pack, we actually have a set of instantiated locations. Maintain this set!
   if (OldParm->isParameterPack() && !NewParm->isParameterPack()) {
-    // Add the new parameter to 
+    // Add the new parameter to the instantiated parameter pack.
     CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm);
   } else {
     // Introduce an Old -> New mapping
index 79d6849a6efeb18def5ff4c131c8fc3922b29a8a..c0f9e21b3530c3bec44678a28e06e4301257e1bf 100644 (file)
@@ -68,3 +68,36 @@ itt::thing ith(itr);
 
 itt::rebind<bool> btr;
 itt::rebind_thing<bool> btt(btr);
+
+namespace PR11848 {
+  template<typename T> using U = int;
+
+  template<typename T, typename ...Ts>
+  void f(U<T> i, U<Ts> ...is) { // expected-error {{type 'U<Ts>' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}}
+    return i + f<Ts...>(is...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+  }
+
+  template<typename ...Ts>
+  struct S {
+    S(U<Ts>...ts); // expected-error {{does not contain any unexpanded parameter packs}}
+  };
+
+  template<typename T>
+  struct Hidden1 {
+    template<typename ...Ts>
+    Hidden1(typename T::template U<Ts> ...ts);
+  };
+
+  template<typename T, typename ...Ts>
+  struct Hidden2 {
+    Hidden2(typename T::template U<Ts> ...ts);
+  };
+
+  struct Hide {
+    template<typename T> using U = int;
+  };
+
+  // FIXME: This case crashes clang at the moment.
+  //Hidden1<Hide> h1;
+  Hidden2<Hide, double, char> h2(1, 2);
+}