[cfe-commits] r149697 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp test/CodeGenCXX/mangle-alias-template.cpp

Douglas Gregor dgregor at apple.com
Fri Feb 3 09:16:23 PST 2012


Author: dgregor
Date: Fri Feb  3 11:16:23 2012
New Revision: 149697

URL: http://llvm.org/viewvc/llvm-project?rev=149697&view=rev
Log:
When a pack expansion occurs in the template argument list of an alias
template without a corresponding parameter pack, don't immediately
substitute the alias template. This is under discussion in the C++
committee, and may become ill-formed, but for now we match GCC.


Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
    cfe/trunk/test/CodeGenCXX/mangle-alias-template.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Fri Feb  3 11:16:23 2012
@@ -3484,8 +3484,12 @@
 
   /// \brief - The number of template arguments named in this class
   /// template specialization.
-  unsigned NumArgs;
+  unsigned NumArgs : 31;
 
+  /// \brief Whether this template specialization type is a substituted
+  /// type alias.
+  bool TypeAlias : 1;
+    
   TemplateSpecializationType(TemplateName T,
                              const TemplateArgument *Args,
                              unsigned NumArgs, QualType Canon,
@@ -3527,9 +3531,23 @@
     return isa<InjectedClassNameType>(getCanonicalTypeInternal());
   }
 
-  /// True if this template specialization type is for a type alias
-  /// template.
-  bool isTypeAlias() const;
+  /// \brief Determine if this template specialization type is for a type alias
+  /// template that has been substituted.
+  ///
+  /// Nearly every template specialization type whose template is an alias
+  /// template will be substituted. However, this is not the case when
+  /// the specialization contains a pack expansion but the template alias
+  /// does not have a corresponding parameter pack, e.g.,
+  ///
+  /// \code
+  /// template<typename T, typename U, typename V> struct S;
+  /// template<typename T, typename U> using A = S<T, int, U>;
+  /// template<typename... Ts> struct X {
+  ///   typedef A<Ts...> type; // not a type alias
+  /// };
+  /// \endcode
+  bool isTypeAlias() const { return TypeAlias; }
+    
   /// Get the aliased type, if this is a specialization of a type alias
   /// template.
   QualType getAliasedType() const {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb  3 11:16:23 2012
@@ -4133,12 +4133,18 @@
   /// \param Converted Will receive the converted, canonicalized template
   /// arguments.
   ///
+  ///
+  /// \param ExpansionIntoFixedList If non-NULL, will be set true to indicate
+  /// when the template arguments contain a pack expansion that is being
+  /// expanded into a fixed parameter list.
+  ///
   /// \returns True if an error occurred, false otherwise.
   bool CheckTemplateArgumentList(TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
                                  TemplateArgumentListInfo &TemplateArgs,
                                  bool PartialTemplateArgs,
-                           SmallVectorImpl<TemplateArgument> &Converted);
+                           SmallVectorImpl<TemplateArgument> &Converted,
+                                 bool *ExpansionIntoFixedList = 0);
 
   bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
                                  const TemplateArgumentLoc &Arg,

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Feb  3 11:16:23 2012
@@ -2450,6 +2450,17 @@
                                        Underlying);
 }
 
+#ifndef NDEBUG
+static bool hasAnyPackExpansions(const TemplateArgument *Args,
+                                 unsigned NumArgs) {
+  for (unsigned I = 0; I != NumArgs; ++I)
+    if (Args[I].isPackExpansion())
+      return true;
+  
+  return true;
+}
+#endif
+
 QualType
 ASTContext::getTemplateSpecializationType(TemplateName Template,
                                           const TemplateArgument *Args,
@@ -2461,16 +2472,18 @@
   if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
     Template = TemplateName(QTN->getTemplateDecl());
   
-  bool isTypeAlias = 
+  bool IsTypeAlias = 
     Template.getAsTemplateDecl() &&
     isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
-
   QualType CanonType;
   if (!Underlying.isNull())
     CanonType = getCanonicalType(Underlying);
   else {
-    assert(!isTypeAlias &&
-           "Underlying type for template alias must be computed by caller");
+    // We can get here with an alias template when the specialization contains
+    // a pack expansion that does not match up with a parameter pack.
+    assert((!IsTypeAlias || hasAnyPackExpansions(Args, NumArgs)) &&
+           "Caller must compute aliased type");
+    IsTypeAlias = false;
     CanonType = getCanonicalTemplateSpecializationType(Template, Args,
                                                        NumArgs);
   }
@@ -2480,13 +2493,11 @@
   // we don't unique and don't want to lose.
   void *Mem = Allocate(sizeof(TemplateSpecializationType) +
                        sizeof(TemplateArgument) * NumArgs +
-                       (isTypeAlias ? sizeof(QualType) : 0),
+                       (IsTypeAlias? sizeof(QualType) : 0),
                        TypeAlignment);
   TemplateSpecializationType *Spec
-    = new (Mem) TemplateSpecializationType(Template,
-                                           Args, NumArgs,
-                                           CanonType,
-                                         isTypeAlias ? Underlying : QualType());
+    = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, CanonType,
+                                         IsTypeAlias ? Underlying : QualType());
 
   Types.push_back(Spec);
   return QualType(Spec, 0);
@@ -2498,9 +2509,6 @@
                                                    unsigned NumArgs) const {
   assert(!Template.getAsDependentTemplateName() && 
          "No dependent template names here!");
-  assert((!Template.getAsTemplateDecl() ||
-          !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
-         "Underlying type for template alias must be computed by caller");
 
   // Look through qualified template names.
   if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Fri Feb  3 11:16:23 2012
@@ -1884,7 +1884,7 @@
          false,
          Canon.isNull()? T.containsUnexpandedParameterPack()
                        : Canon->containsUnexpandedParameterPack()),
-    Template(T), NumArgs(NumArgs) {
+    Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
   assert(!T.getAsDependentTemplateName() && 
          "Use DependentTemplateSpecializationType for dependent template-name");
   assert((T.getKind() == TemplateName::Template ||
@@ -1923,10 +1923,7 @@
   }
 
   // Store the aliased type if this is a type alias template specialization.
-  bool IsTypeAlias = !AliasedType.isNull();
-  assert(IsTypeAlias == isTypeAlias() &&
-         "allocated wrong size for type alias");
-  if (IsTypeAlias) {
+  if (TypeAlias) {
     TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
     *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
   }
@@ -1943,11 +1940,6 @@
     Args[Idx].Profile(ID, Context);
 }
 
-bool TemplateSpecializationType::isTypeAlias() const {
-  TemplateDecl *D = Template.getAsTemplateDecl();
-  return D && isa<TypeAliasTemplateDecl>(D);
-}
-
 QualType
 QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
   if (!hasNonFastQualifiers())

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Feb  3 11:16:23 2012
@@ -1918,15 +1918,17 @@
   // Check that the template argument list is well-formed for this
   // template.
   SmallVector<TemplateArgument, 4> Converted;
+  bool ExpansionIntoFixedList = false;
   if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
-                                false, Converted))
+                                false, Converted, &ExpansionIntoFixedList))
     return QualType();
 
   QualType CanonType;
 
   bool InstantiationDependent = false;
-  if (TypeAliasTemplateDecl *AliasTemplate
-        = dyn_cast<TypeAliasTemplateDecl>(Template)) {
+  TypeAliasTemplateDecl *AliasTemplate = 0;
+  if (!ExpansionIntoFixedList &&
+      (AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template))) {
     // Find the canonical type for this type alias template specialization.
     TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
     if (Pattern->isInvalidDecl())
@@ -2891,7 +2893,11 @@
                                      SourceLocation TemplateLoc,
                                      TemplateArgumentListInfo &TemplateArgs,
                                      bool PartialTemplateArgs,
-                          SmallVectorImpl<TemplateArgument> &Converted) {
+                          SmallVectorImpl<TemplateArgument> &Converted,
+                                     bool *ExpansionIntoFixedList) {
+  if (ExpansionIntoFixedList)
+    *ExpansionIntoFixedList = false;
+
   TemplateParameterList *Params = Template->getTemplateParameters();
   unsigned NumParams = Params->size();
   unsigned NumArgs = TemplateArgs.size();
@@ -2901,7 +2907,7 @@
 
   bool HasParameterPack =
     NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
+  
   // C++ [temp.arg]p1:
   //   [...] The type and form of each template-argument specified in
   //   a template-id shall match the type and form specified for the
@@ -3088,6 +3094,9 @@
                                            ArgumentPack.size()));
         ArgumentPack.clear();
       }      
+    } else if (ExpansionIntoFixedList) {
+      // We have expanded a pack into a fixed list.
+      *ExpansionIntoFixedList = true;
     }
 
     return Invalid;

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp Fri Feb  3 11:16:23 2012
@@ -118,3 +118,10 @@
   X0<int, float> x0if;
   X0<int, float, double> x0ifd;
 }
+
+namespace FixedAliasTemplate {
+  template<typename,typename,typename> struct S {};
+  template<typename T, typename U> using U = S<T, int, U>;
+  template<typename...Ts> U<Ts...> &f(U<Ts...>, Ts...);
+  S<int, int, double> &s1 = f({}, 0, 0.0);
+}

Modified: cfe/trunk/test/CodeGenCXX/mangle-alias-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-alias-template.cpp?rev=149697&r1=149696&r2=149697&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-alias-template.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-alias-template.cpp Fri Feb  3 11:16:23 2012
@@ -11,6 +11,10 @@
 
 template<template<typename> class F> void h(F<int>);
 
+template<typename,typename,typename> struct S {};
+template<typename T, typename U> using U = S<T, int, U>;
+template<typename...Ts> void h(U<Ts...>, Ts...);
+
 // CHECK: define void @_Z1zv(
 void z() {
   vector<int> VI;
@@ -38,4 +42,7 @@
   Vec<Vec<int>> VVI;
   g(VVI);
   // CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
+
+  // CHECK: call void @_Z1hIJidEEv1UIDpT_ES2_
+  h({}, 0, 0.0);
 }





More information about the cfe-commits mailing list