]> granicus.if.org Git - clang/commitdiff
Variadic templates: extend Type, NestedNameSpecifier, TemplateName,
authorDouglas Gregor <dgregor@apple.com>
Mon, 13 Dec 2010 22:49:22 +0000 (22:49 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 13 Dec 2010 22:49:22 +0000 (22:49 +0000)
and TemplateArgument with an operation that determines whether there
are any unexpanded parameter packs within that construct. Use this
information to diagnose the appearance of the names of parameter packs
that have not been expanded (C++ [temp.variadic]p5). Since this
property is checked often (every declaration, ever expression
statement, etc.), we extend Type and Expr with a bit storing the
result of this computation, rather than walking the AST each time to
determine whether any unexpanded parameter packs occur.

This commit is deficient in several ways, which will be remedied with
future commits:
  - Expr has a bit to store the presence of an unexpanded parameter
  pack, but it is never set.
  - The error messages don't point out where the unexpanded parameter
  packs were named in the type/expression, but they should.
  - We don't check for unexpanded parameter packs in all of the places
  where we should.
  - Testing is sparse, pending the resolution of the above three
  issues.

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

20 files changed:
include/clang/AST/DeclTemplate.h
include/clang/AST/Expr.h
include/clang/AST/NestedNameSpecifier.h
include/clang/AST/Stmt.h
include/clang/AST/TemplateBase.h
include/clang/AST/TemplateName.h
include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/NestedNameSpecifier.cpp
lib/AST/TemplateBase.cpp
lib/AST/TemplateName.cpp
lib/AST/Type.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CXX/temp/temp.decls/temp.variadic/p5.cpp [new file with mode: 0644]

index 6e79bad6823ed61f32021e491007fd527aa0b0d9..6628b3ffb020d5202c07602b6dd950753667c7d5 100644 (file)
@@ -1080,6 +1080,14 @@ public:
   using TemplateParmPosition::getPosition;
   using TemplateParmPosition::getIndex;
 
+  /// \brief Whether this template template parameter is a template
+  /// parameter pack.
+  ///
+  /// \code
+  /// template<template <class T> ...MetaFunctions> struct Apply;
+  /// \endcode
+  bool isParameterPack() const { return /*FIXME: variadic templates*/false; }
+
   /// \brief Determine whether this template parameter has a default
   /// argument.
   bool hasDefaultArgument() const {
index c288ec6ea1a0bcc55db55ce724d60b4c93ff2bfb..5039baa03a9243b7d5a4d9b763368b1cae128f17 100644 (file)
@@ -62,6 +62,8 @@ protected:
     ExprBits.ValueDependent = VD;
     ExprBits.ValueKind = VK;
     ExprBits.ObjectKind = OK;
+    // FIXME: Variadic templates.
+    ExprBits.ContainsUnexpandedParameterPack = false;
     setType(T);
   }
 
@@ -112,6 +114,24 @@ public:
   /// \brief Set whether this expression is type-dependent or not.
   void setTypeDependent(bool TD) { ExprBits.TypeDependent = TD; }
 
+  /// \brief Whether this expression contains an unexpanded parameter
+  /// pack (for C++0x variadic templates).
+  ///
+  /// Given the following function template:
+  ///
+  /// \code
+  /// template<typename F, typename ...Types>
+  /// void forward(const F &f, Types &&...args) {
+  ///   f(static_cast<Types&&>(args)...);
+  /// }
+  /// \endcode
+  ///
+  /// The expressions \c args and \c static_cast<Types&&>(args) both
+  /// contain parameter packs.
+  bool containsUnexpandedParameterPack() const { 
+    return ExprBits.ContainsUnexpandedParameterPack; 
+  }
+
   /// SourceLocation tokens are not useful in isolation - they are low level
   /// value objects created/interpreted by SourceManager. We assume AST
   /// clients will have a pointer to the respective SourceManager.
index 3b25f3bb403ffa3160460e178a217cd19f516b6a..41389da36b8ed502763fe8bcbbf2c14a51c43ebb 100644 (file)
@@ -172,6 +172,10 @@ public:
   /// type or not.
   bool isDependent() const;
 
+  /// \brief Whether this nested-name-specifier contains an unexpanded
+  /// parameter pack (for C++0x variadic templates).
+  bool containsUnexpandedParameterPack() const;
+
   /// \brief Print this nested name specifier to the given output
   /// stream.
   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
index 421c59661b520c447eb43957a3a1b2e83f0a0597..124977d97ffc9f99e6417db9b78f8ef34993bd5c 100644 (file)
@@ -143,14 +143,16 @@ protected:
     friend class DeclRefExpr; // computeDependence
     friend class InitListExpr; // ctor
     friend class DesignatedInitExpr; // ctor
+    friend class ASTStmtReader;
     unsigned : NumStmtBits;
 
     unsigned ValueKind : 2;
     unsigned ObjectKind : 2;
     unsigned TypeDependent : 1;
     unsigned ValueDependent : 1;
+    unsigned ContainsUnexpandedParameterPack : 1;
   };
-  enum { NumExprBits = 14 };
+  enum { NumExprBits = 15 };
 
   class CastExprBitfields {
     friend class CastExpr;
@@ -168,6 +170,8 @@ protected:
     CastExprBitfields CastExprBits;
   };
 
+  friend class ASTStmtReader;
+
 public:
   // Only allow allocation of Stmts using the allocator in ASTContext
   // or by doing a placement new.
index 3fe77405ae4defcb816024a6ca8cea7eb952dd7e..e5057e547e82f4d10c11bd2a0e64ac200820862d 100644 (file)
@@ -182,6 +182,10 @@ public:
   /// \brief Determine whether this template argument has no value.
   bool isNull() const { return Kind == Null; }
 
+  /// \brief Whether this template argument contains an unexpanded
+  /// parameter pack.
+  bool containsUnexpandedParameterPack() const;
+
   /// \brief Retrieve the template argument as a type.
   QualType getAsType() const {
     if (Kind != Type)
index ddfac712734bf263855d8d5bc93c5475395e2b8c..9b213a3b7aa57d291bf4c54d2c12c3aa9b5c6420 100644 (file)
@@ -157,6 +157,10 @@ public:
   /// \brief Determines whether this is a dependent template name.
   bool isDependent() const;
 
+  /// \brief Determines whether this template name contains an
+  /// unexpanded parameter pack (for C++0x variadic templates).
+  bool containsUnexpandedParameterPack() const;
+
   /// \brief Print the template name.
   ///
   /// \param OS the output stream to which the template name will be
index 81230b7a54af91784ef715b1bbd8e59504645e71..ba588ec1aae222ab0a25f585b739900fc3d6f7a5 100644 (file)
@@ -851,6 +851,10 @@ private:
   
     /// \brief Whether this type is a variably-modified type (C99 6.7.5).
     unsigned VariablyModified : 1;
+
+    /// \brief Whether this type contains an unexpanded parameter pack
+    /// (for C++0x variadic templates).
+    unsigned ContainsUnexpandedParameterPack : 1;
   
     /// \brief Nonzero if the cache (i.e. the bitfields here starting
     /// with 'Cache') is valid.  If so, then this is a
@@ -882,7 +886,7 @@ private:
       return CachedLocalOrUnnamed;
     }
   };
-  enum { NumTypeBits = 16 };
+  enum { NumTypeBits = 17 };
 
 protected:
   // These classes allow subclasses to somewhat cleanly pack bitfields
@@ -1010,12 +1014,14 @@ private:
 protected:
   // silence VC++ warning C4355: 'this' : used in base member initializer list
   Type *this_() { return this; }
-  Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified)
+  Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified,
+       bool ContainsUnexpandedParameterPack)
     : ExtQualsTypeCommonBase(this), 
       CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical) {
     TypeBits.TC = tc;
     TypeBits.Dependent = Dependent;
     TypeBits.VariablyModified = VariablyModified;
+    TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
     TypeBits.CacheValidAndVisibility = 0;
     TypeBits.CachedLocalOrUnnamed = false;
     TypeBits.CachedLinkage = NoLinkage;
@@ -1025,13 +1031,35 @@ protected:
 
   void setDependent(bool D = true) { TypeBits.Dependent = D; }
   void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; }
-  
+  void setContainsUnexpandedParameterPack(bool PP = true) {
+    TypeBits.ContainsUnexpandedParameterPack = PP;
+  }
+
 public:
   TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); }
 
   /// \brief Whether this type comes from an AST file.
   bool isFromAST() const { return TypeBits.FromAST; }
 
+  /// \brief Whether this type is or contains an unexpanded parameter
+  /// pack, used to support C++0x variadic templates.
+  ///
+  /// A type that contains a parameter pack shall be expanded by the
+  /// ellipsis operator at some point. For example, the typedef in the
+  /// following example contains an unexpanded parameter pack 'T':
+  ///
+  /// \code
+  /// template<typename ...T>
+  /// struct X {
+  ///   typedef T* pointer_types; // ill-formed; T is a parameter pack.
+  /// };
+  /// \endcode
+  ///
+  /// Note that this routine does not specify which 
+  bool containsUnexpandedParameterPack() const { 
+    return TypeBits.ContainsUnexpandedParameterPack;
+  }
+
   bool isCanonicalUnqualified() const {
     return CanonicalType.getTypePtr() == this;
   }
@@ -1363,7 +1391,8 @@ public:
 public:
   BuiltinType(Kind K)
     : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
-           /*VariablyModified=*/false) {
+           /*VariablyModified=*/false,
+           /*Unexpanded paramter pack=*/false) {
     BuiltinTypeBits.Kind = K;
   }
 
@@ -1408,7 +1437,8 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
   QualType ElementType;
   ComplexType(QualType Element, QualType CanonicalPtr) :
     Type(Complex, CanonicalPtr, Element->isDependentType(),
-         Element->isVariablyModifiedType()),
+         Element->isVariablyModifiedType(),
+         Element->containsUnexpandedParameterPack()),
     ElementType(Element) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1437,7 +1467,8 @@ class ParenType : public Type, public llvm::FoldingSetNode {
 
   ParenType(QualType InnerType, QualType CanonType) :
     Type(Paren, CanonType, InnerType->isDependentType(),
-         InnerType->isVariablyModifiedType()),
+         InnerType->isVariablyModifiedType(),
+         InnerType->containsUnexpandedParameterPack()),
     Inner(InnerType) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1467,7 +1498,8 @@ class PointerType : public Type, public llvm::FoldingSetNode {
 
   PointerType(QualType Pointee, QualType CanonicalPtr) :
     Type(Pointer, CanonicalPtr, Pointee->isDependentType(),
-         Pointee->isVariablyModifiedType()), 
+         Pointee->isVariablyModifiedType(),
+         Pointee->containsUnexpandedParameterPack()), 
     PointeeType(Pointee) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1498,7 +1530,8 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
   QualType PointeeType;  // Block is some kind of pointer type
   BlockPointerType(QualType Pointee, QualType CanonicalCls) :
     Type(BlockPointer, CanonicalCls, Pointee->isDependentType(),
-         Pointee->isVariablyModifiedType()),
+         Pointee->isVariablyModifiedType(),
+         Pointee->containsUnexpandedParameterPack()),
     PointeeType(Pointee) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1533,7 +1566,10 @@ protected:
   ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef,
                 bool SpelledAsLValue) :
     Type(tc, CanonicalRef, Referencee->isDependentType(),
-         Referencee->isVariablyModifiedType()), PointeeType(Referencee) {
+         Referencee->isVariablyModifiedType(),
+         Referencee->containsUnexpandedParameterPack()), 
+    PointeeType(Referencee) 
+  {
     ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue;
     ReferenceTypeBits.InnerRef = Referencee->isReferenceType();
   }
@@ -1614,7 +1650,9 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
   MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
     Type(MemberPointer, CanonicalPtr,
          Cls->isDependentType() || Pointee->isDependentType(),
-         Pointee->isVariablyModifiedType()),
+         Pointee->isVariablyModifiedType(),
+         (Cls->containsUnexpandedParameterPack() || 
+          Pointee->containsUnexpandedParameterPack())),
     PointeeType(Pointee), Class(Cls) {
   }
   friend class ASTContext; // ASTContext creates these.
@@ -1676,9 +1714,11 @@ protected:
   //       size is specified by a constant expression that is
   //       value-dependent,
   ArrayType(TypeClass tc, QualType et, QualType can,
-            ArraySizeModifier sm, unsigned tq)
+            ArraySizeModifier sm, unsigned tq,
+            bool ContainsUnexpandedParameterPack)
     : Type(tc, can, et->isDependentType() || tc == DependentSizedArray,
-           (tc == VariableArray || et->isVariablyModifiedType())),
+           (tc == VariableArray || et->isVariablyModifiedType()),
+           ContainsUnexpandedParameterPack),
       ElementType(et) {
     ArrayTypeBits.IndexTypeQuals = tq;
     ArrayTypeBits.SizeModifier = sm;
@@ -1716,12 +1756,14 @@ class ConstantArrayType : public ArrayType {
 
   ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
                     ArraySizeModifier sm, unsigned tq)
-    : ArrayType(ConstantArray, et, can, sm, tq),
+    : ArrayType(ConstantArray, et, can, sm, tq,
+                et->containsUnexpandedParameterPack()),
       Size(size) {}
 protected:
   ConstantArrayType(TypeClass tc, QualType et, QualType can,
                     const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
-    : ArrayType(tc, et, can, sm, tq), Size(size) {}
+    : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), 
+      Size(size) {}
   friend class ASTContext;  // ASTContext creates these.
 public:
   const llvm::APInt &getSize() const { return Size; }
@@ -1764,7 +1806,8 @@ class IncompleteArrayType : public ArrayType {
 
   IncompleteArrayType(QualType et, QualType can,
                       ArraySizeModifier sm, unsigned tq)
-    : ArrayType(IncompleteArray, et, can, sm, tq) {}
+    : ArrayType(IncompleteArray, et, can, sm, tq, 
+                et->containsUnexpandedParameterPack()) {}
   friend class ASTContext;  // ASTContext creates these.
 public:
   bool isSugared() const { return false; }
@@ -1815,7 +1858,8 @@ class VariableArrayType : public ArrayType {
   VariableArrayType(QualType et, QualType can, Expr *e,
                     ArraySizeModifier sm, unsigned tq,
                     SourceRange brackets)
-    : ArrayType(VariableArray, et, can, sm, tq),
+    : ArrayType(VariableArray, et, can, sm, tq, 
+                et->containsUnexpandedParameterPack()),
       SizeExpr((Stmt*) e), Brackets(brackets) {}
   friend class ASTContext;  // ASTContext creates these.
 
@@ -1872,9 +1916,8 @@ class DependentSizedArrayType : public ArrayType {
 
   DependentSizedArrayType(ASTContext &Context, QualType et, QualType can,
                           Expr *e, ArraySizeModifier sm, unsigned tq,
-                          SourceRange brackets)
-    : ArrayType(DependentSizedArray, et, can, sm, tq),
-      Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {}
+                          SourceRange brackets);
+
   friend class ASTContext;  // ASTContext creates these.
 
 public:
@@ -1924,11 +1967,8 @@ class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
   SourceLocation loc;
 
   DependentSizedExtVectorType(ASTContext &Context, QualType ElementType,
-                              QualType can, Expr *SizeExpr, SourceLocation loc)
-    : Type(DependentSizedExtVector, can, /*Dependent=*/true,
-           ElementType->isVariablyModifiedType()),
-      Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
-      loc(loc) {}
+                              QualType can, Expr *SizeExpr, SourceLocation loc);
+
   friend class ASTContext;
 
 public:
@@ -1973,20 +2013,11 @@ protected:
   QualType ElementType;
 
   VectorType(QualType vecType, unsigned nElements, QualType canonType,
-             VectorKind vecKind) :
-    Type(Vector, canonType, vecType->isDependentType(),
-         vecType->isVariablyModifiedType()), ElementType(vecType) {
-    VectorTypeBits.VecKind = vecKind;
-    VectorTypeBits.NumElements = nElements;
-  }
+             VectorKind vecKind);
   
   VectorType(TypeClass tc, QualType vecType, unsigned nElements,
-             QualType canonType, VectorKind vecKind)
-    : Type(tc, canonType, vecType->isDependentType(),
-           vecType->isVariablyModifiedType()), ElementType(vecType) {
-    VectorTypeBits.VecKind = vecKind;
-    VectorTypeBits.NumElements = nElements;
-  }
+             QualType canonType, VectorKind vecKind);
+
   friend class ASTContext;  // ASTContext creates these.
   
 public:
@@ -2173,8 +2204,11 @@ class FunctionType : public Type {
 protected:
   FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
                unsigned typeQuals, QualType Canonical, bool Dependent,
-               bool VariablyModified, ExtInfo Info)
-    : Type(tc, Canonical, Dependent, VariablyModified), ResultType(res) {
+               bool VariablyModified, bool ContainsUnexpandedParameterPack, 
+               ExtInfo Info)
+    : Type(tc, Canonical, Dependent, VariablyModified, 
+           ContainsUnexpandedParameterPack), 
+      ResultType(res) {
     FunctionTypeBits.ExtInfo = Info.Bits;
     FunctionTypeBits.SubclassInfo = SubclassInfo;
     FunctionTypeBits.TypeQuals = typeQuals;
@@ -2211,7 +2245,8 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
   FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
     : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
                    /*Dependent=*/false, Result->isVariablyModifiedType(), 
-                   Info) {}
+                   /*ContainsUnexpandedParameterPack=*/false, Info) {}
+
   friend class ASTContext;  // ASTContext creates these.
   
 public:
@@ -2241,6 +2276,17 @@ public:
 /// exception specification, but this specification is not part of the canonical
 /// type.
 class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
+  /// \brief Determine whether there are any argument types that
+  /// contain an unexpanded parameter pack.
+  static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, 
+                                                 unsigned numArgs) {
+    for (unsigned Idx = 0; Idx < numArgs; ++Idx)
+      if (ArgArray[Idx]->containsUnexpandedParameterPack())
+        return true;
+
+    return false;
+  }
+
   FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
                     bool isVariadic, unsigned typeQuals, bool hasExs,
                     bool hasAnyExs, const QualType *ExArray,
@@ -2330,7 +2376,8 @@ class UnresolvedUsingType : public Type {
   UnresolvedUsingTypenameDecl *Decl;
 
   UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
-    : Type(UnresolvedUsing, QualType(), true, false),
+    : Type(UnresolvedUsing, QualType(), true, false, 
+           /*ContainsUnexpandedParameterPack=*/false),
       Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {}
   friend class ASTContext; // ASTContext creates these.
 public:
@@ -2359,7 +2406,8 @@ class TypedefType : public Type {
   TypedefDecl *Decl;
 protected:
   TypedefType(TypeClass tc, const TypedefDecl *D, QualType can)
-    : Type(tc, can, can->isDependentType(), can->isVariablyModifiedType()),
+    : Type(tc, can, can->isDependentType(), can->isVariablyModifiedType(), 
+           /*ContainsUnexpandedParameterPack=*/false),
       Decl(const_cast<TypedefDecl*>(D)) {
     assert(!isa<TypedefType>(can) && "Invalid canonical type");
   }
@@ -2424,7 +2472,8 @@ public:
 class TypeOfType : public Type {
   QualType TOType;
   TypeOfType(QualType T, QualType can)
-    : Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType()), 
+    : Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType(), 
+           T->containsUnexpandedParameterPack()), 
       TOType(T) {
     assert(!isa<TypedefType>(can) && "Invalid canonical type");
   }
@@ -2579,12 +2628,12 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
   TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
                        QualType Canon)
     : Type(TemplateTypeParm, Canon, /*Dependent=*/true,
-           /*VariablyModified=*/false),
+           /*VariablyModified=*/false, PP),
       Depth(D), ParameterPack(PP), Index(I), Name(N) { }
 
   TemplateTypeParmType(unsigned D, unsigned I, bool PP)
     : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true,
-           /*VariablyModified=*/false),
+           /*VariablyModified=*/false, PP),
       Depth(D), ParameterPack(PP), Index(I), Name(0) { }
 
   friend class ASTContext;  // ASTContext creates these
@@ -2630,7 +2679,8 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
 
   SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon)
     : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(),
-           Canon->isVariablyModifiedType()),
+           Canon->isVariablyModifiedType(),
+           Canon->containsUnexpandedParameterPack()),
       Replaced(Param) { }
 
   friend class ASTContext;
@@ -2805,7 +2855,8 @@ class InjectedClassNameType : public Type {
                           // interdependencies.
   InjectedClassNameType(CXXRecordDecl *D, QualType TST)
     : Type(InjectedClassName, QualType(), /*Dependent=*/true,
-           /*VariablyModified=*/false),
+           /*VariablyModified=*/false, 
+           /*ContainsUnexpandedParameterPack=*/false),
       Decl(D), InjectedType(TST) {
     assert(isa<TemplateSpecializationType>(TST));
     assert(!TST.hasQualifiers());
@@ -2866,8 +2917,10 @@ enum ElaboratedTypeKeyword {
 class TypeWithKeyword : public Type {
 protected:
   TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
-                  QualType Canonical, bool Dependent, bool VariablyModified)
-    : Type(tc, Canonical, Dependent, VariablyModified) {
+                  QualType Canonical, bool Dependent, bool VariablyModified, 
+                  bool ContainsUnexpandedParameterPack)
+  : Type(tc, Canonical, Dependent, VariablyModified, 
+         ContainsUnexpandedParameterPack) {
     TypeWithKeywordBits.Keyword = Keyword;
   }
 
@@ -2926,7 +2979,8 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
                  QualType NamedType, QualType CanonType)
     : TypeWithKeyword(Keyword, Elaborated, CanonType,
                       NamedType->isDependentType(),
-                      NamedType->isVariablyModifiedType()),
+                      NamedType->isVariablyModifiedType(),
+                      NamedType->containsUnexpandedParameterPack()),
       NNS(NNS), NamedType(NamedType) {
     assert(!(Keyword == ETK_None && NNS == 0) &&
            "ElaboratedType cannot have elaborated type keyword "
@@ -2987,7 +3041,8 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
   DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, 
                     const IdentifierInfo *Name, QualType CanonType)
     : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true,
-                      /*VariablyModified=*/false),
+                      /*VariablyModified=*/false,
+                      NNS->containsUnexpandedParameterPack()),
       NNS(NNS), Name(Name) {
     assert(NNS->isDependent() &&
            "DependentNameType requires a dependent nested-name-specifier");
@@ -3148,7 +3203,7 @@ protected:
 
   enum Nonce_ObjCInterface { Nonce_ObjCInterface };
   ObjCObjectType(enum Nonce_ObjCInterface)
-    : Type(ObjCInterface, QualType(), false, false),
+        : Type(ObjCInterface, QualType(), false, false, false),
       BaseType(QualType(this_(), 0)) {
     ObjCObjectTypeBits.NumProtocols = 0;
   }
@@ -3305,7 +3360,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
   QualType PointeeType;
 
   ObjCObjectPointerType(QualType Canonical, QualType Pointee)
-    : Type(ObjCObjectPointer, Canonical, false, false),
+    : Type(ObjCObjectPointer, Canonical, false, false, false),
       PointeeType(Pointee) {}
   friend class ASTContext;  // ASTContext creates these.
 
index 1b23aaaf638926964f61996a3f7d51c951b342be..3675ca953c76ab142854d1a1b2fdfafc336da133 100644 (file)
@@ -1821,6 +1821,10 @@ def note_template_parameter_pack_here : Note<
   "previous template %select{type|non-type|template}0 "
   "parameter%select{| pack}1 declared here">;
   
+def err_unexpanded_parameter_pack : Error<
+  "%select{expression|base type|declaration type|template argument}0 contains "
+  "unexpanded parameter pack">;
+
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
 def err_unexpected_namespace : Error<
index 4df4b7b53542115ae4abe565eb63ea8395919431..dd8ae51e90080c98bde59553124afbe1ecb96d09 100644 (file)
@@ -165,7 +165,9 @@ class LocInfoType : public Type {
 
   LocInfoType(QualType ty, TypeSourceInfo *TInfo)
     : Type((TypeClass)LocInfo, ty, ty->isDependentType(), 
-           ty->isVariablyModifiedType()), DeclInfo(TInfo) {
+           ty->isVariablyModifiedType(),
+           ty->containsUnexpandedParameterPack()), 
+      DeclInfo(TInfo) {
     assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
   }
   friend class Sema;
@@ -3127,6 +3129,40 @@ public:
                                   const TemplateArgument *Args,
                                   unsigned NumArgs);
 
+  /// \brief The context in which an unexpanded parameter pack is
+  /// being diagnosed.
+  ///
+  /// Note that the values of this enumeration line up with the first
+  /// argument to the \c err_unexpanded_parameter_pack diagnostic.
+  enum UnexpandedParameterPackContext {
+    UPPC_Expression = 0,
+    UPPC_BaseType,
+    UPPC_DeclarationType,
+    UPPC_TemplateArgument
+  };
+
+  /// \brief If the given type contains an unexpanded parameter pack,
+  /// diagnose the error.
+  ///
+  /// \param Loc The source location where a diagnostc should be emitted.
+  ///
+  /// \param T The type that is being checked for unexpanded parameter
+  /// packs.
+  ///
+  /// \returns true if an error ocurred, false otherwise.
+  bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T,
+                                       UnexpandedParameterPackContext UPPC);
+
+  /// \brief If the given expression contains an unexpanded parameter
+  /// pack, diagnose the error.
+  ///
+  /// \param E The expression that is being checked for unexpanded
+  /// parameter packs.
+  ///
+  /// \returns true if an error ocurred, false otherwise.
+  bool DiagnoseUnexpandedParameterPack(Expr *E,
+                       UnexpandedParameterPackContext UPPC = UPPC_Expression);
+
   /// \brief Describes the result of template argument deduction.
   ///
   /// The TemplateDeductionResult enumeration describes the result of
index 212def8565ea715e84a1efdfe6865f3a04e31799..10035acdcf3946e719a32c2ca91832d8c088dcea 100644 (file)
@@ -113,6 +113,24 @@ bool NestedNameSpecifier::isDependent() const {
   return false;
 }
 
+bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
+  switch (getKind()) {
+  case Identifier:
+    return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
+
+  case Namespace:
+  case Global:
+    return false;
+
+  case TypeSpec:
+  case TypeSpecWithTemplate:
+    return getAsType()->containsUnexpandedParameterPack();
+  }
+
+  // Necessary to suppress a GCC warning.
+  return false;  
+}
+
 /// \brief Print this nested name specifier to the given output
 /// stream.
 void
index 4a1ebb46c1e278ea3e0ebedfd47587fa8d7442f4..ef2deea8c8429ed3a422ec9a1f1218b8017054fa 100644 (file)
@@ -26,6 +26,39 @@ using namespace clang;
 // TemplateArgument Implementation
 //===----------------------------------------------------------------------===//
 
+bool TemplateArgument::containsUnexpandedParameterPack() const {
+  switch (getKind()) {
+  case Null:
+  case Declaration:
+  case Integral:
+    break;
+
+  case Type:
+    if (getAsType()->containsUnexpandedParameterPack())
+      return true;
+    break;
+
+  case Template:
+    if (getAsTemplate().containsUnexpandedParameterPack())
+      return true;
+    break;
+        
+  case Expression:
+    if (getAsExpr()->containsUnexpandedParameterPack())
+      return true;
+    break;
+
+  case Pack:
+    for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P)
+      if (P->containsUnexpandedParameterPack())
+        return true;
+
+    break;
+  }
+
+  return false;
+}
+
 void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
                                ASTContext &Context) const {
   ID.AddInteger(Kind);
index 439f4e81ade2c81bcccd92ddb3159ced4886babc..73ff402b074e8612a9d4dca405ed8762da7272a5 100644 (file)
@@ -60,6 +60,22 @@ bool TemplateName::isDependent() const {
   return true;
 }
 
+bool TemplateName::containsUnexpandedParameterPack() const {
+  if (TemplateDecl *Template = getAsTemplateDecl()) {
+    if (TemplateTemplateParmDecl *TTP 
+                                  = dyn_cast<TemplateTemplateParmDecl>(Template))
+      return TTP->isParameterPack();
+
+    return false;
+  }
+
+  if (DependentTemplateName *DTN = getAsDependentTemplateName())
+    return DTN->getQualifier() && 
+      DTN->getQualifier()->containsUnexpandedParameterPack();
+
+  return false;
+}
+
 void
 TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
                     bool SuppressNNS) const {
index ed05a39305ba376620aeff95d8c865f0b6d69131..127613ed32ea161d2226aa443509bfcf71af41af 100644 (file)
@@ -63,6 +63,18 @@ unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) {
   return Bits;
 }
 
+DependentSizedArrayType::DependentSizedArrayType(ASTContext &Context, 
+                                                 QualType et, QualType can,
+                                                 Expr *e, ArraySizeModifier sm,
+                                                 unsigned tq,
+                                                 SourceRange brackets)
+    : ArrayType(DependentSizedArray, et, can, sm, tq, 
+                (et->containsUnexpandedParameterPack() ||
+                 (e && e->containsUnexpandedParameterPack()))),
+      Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) 
+{
+}
+
 void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
                                       ASTContext &Context,
                                       QualType ET,
@@ -75,6 +87,20 @@ void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
   E->Profile(ID, Context, true);
 }
 
+DependentSizedExtVectorType::DependentSizedExtVectorType(ASTContext &Context, 
+                                                         QualType ElementType,
+                                                         QualType can, 
+                                                         Expr *SizeExpr, 
+                                                         SourceLocation loc)
+    : Type(DependentSizedExtVector, can, /*Dependent=*/true,
+           ElementType->isVariablyModifiedType(), 
+           (ElementType->containsUnexpandedParameterPack() ||
+            (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))),
+      Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
+      loc(loc) 
+{
+}
+
 void
 DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
                                      ASTContext &Context,
@@ -83,6 +109,28 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
   SizeExpr->Profile(ID, Context, true);
 }
 
+VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
+                       VectorKind vecKind)
+  : Type(Vector, canonType, vecType->isDependentType(),
+         vecType->isVariablyModifiedType(),
+         vecType->containsUnexpandedParameterPack()),
+    ElementType(vecType) 
+{
+  VectorTypeBits.VecKind = vecKind;
+  VectorTypeBits.NumElements = nElements;
+}
+
+VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements,
+                       QualType canonType, VectorKind vecKind)
+  : Type(tc, canonType, vecType->isDependentType(),
+         vecType->isVariablyModifiedType(),
+         vecType->containsUnexpandedParameterPack()), 
+    ElementType(vecType) 
+{
+  VectorTypeBits.VecKind = vecKind;
+  VectorTypeBits.NumElements = nElements;
+}
+
 /// getArrayElementTypeNoTypeQual - If this is an array type, return the
 /// element type of the array, potentially with type qualifiers missing.
 /// This method should never be used when type qualifiers are meaningful.
@@ -321,8 +369,9 @@ const RecordType *Type::getAsUnionType() const {
 ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
                                ObjCProtocolDecl * const *Protocols,
                                unsigned NumProtocols)
-  : Type(ObjCObject, Canonical, false, false),
-    BaseType(Base) {
+  : Type(ObjCObject, Canonical, false, false, false),
+    BaseType(Base) 
+{
   ObjCObjectTypeBits.NumProtocols = NumProtocols;
   assert(getNumProtocols() == NumProtocols &&
          "bitfield overflow in protocol count");
@@ -924,12 +973,17 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
                          unsigned NumArgs, const TemplateArgument *Args,
                          QualType Canon)
   : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
-                    false),
+                    /*VariablyModified=*/false,
+                    NNS->containsUnexpandedParameterPack()),
     NNS(NNS), Name(Name), NumArgs(NumArgs) {
   assert(NNS && NNS->isDependent() &&
          "DependentTemplateSpecializatonType requires dependent qualifier");
-  for (unsigned I = 0; I != NumArgs; ++I)
+  for (unsigned I = 0; I != NumArgs; ++I) {
+    if (Args[I].containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack();
+
     new (&getArgBuffer()[I]) TemplateArgument(Args[I]);
+  }
 }
 
 void
@@ -1052,6 +1106,7 @@ FunctionProtoType::FunctionProtoType(QualType Result, const QualType *ArgArray,
   : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
                  Result->isDependentType(),
                  Result->isVariablyModifiedType(),
+                 Result->containsUnexpandedParameterPack(),
                  Info),
     NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
     AnyExceptionSpec(hasAnyExs) 
@@ -1061,7 +1116,10 @@ FunctionProtoType::FunctionProtoType(QualType Result, const QualType *ArgArray,
   for (unsigned i = 0; i != numArgs; ++i) {
     if (ArgArray[i]->isDependentType())
       setDependent();
-    
+
+    if (ArgArray[i]->containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack();
+
     ArgInfo[i] = ArgArray[i];
   }
   
@@ -1106,7 +1164,9 @@ QualType TypedefType::desugar() const {
 
 TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
   : Type(TypeOfExpr, can, E->isTypeDependent(), 
-         E->getType()->isVariablyModifiedType()), TOExpr(E) {
+         E->getType()->isVariablyModifiedType(),
+         E->containsUnexpandedParameterPack()), 
+    TOExpr(E) {
 }
 
 QualType TypeOfExprType::desugar() const {
@@ -1120,7 +1180,9 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
 
 DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
   : Type(Decltype, can, E->isTypeDependent(), 
-         E->getType()->isVariablyModifiedType()), E(E),
+         E->getType()->isVariablyModifiedType(), 
+         E->containsUnexpandedParameterPack()), 
+    E(E),
   UnderlyingType(underlyingType) {
 }
 
@@ -1133,7 +1195,8 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
 }
 
 TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
-  : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false),
+  : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false, 
+         /*ContainsUnexpandedParameterPack=*/false),
     decl(const_cast<TagDecl*>(D)) {}
 
 static TagDecl *getInterestingTagDecl(TagDecl *decl) {
@@ -1233,7 +1296,8 @@ TemplateSpecializationType(TemplateName T,
                            unsigned NumArgs, QualType Canon)
   : Type(TemplateSpecialization,
          Canon.isNull()? QualType(this, 0) : Canon,
-         T.isDependent(), false),
+         T.isDependent(), false,
+         T.containsUnexpandedParameterPack()),
     Template(T), NumArgs(NumArgs) 
 {
   assert((!Canon.isNull() ||
@@ -1249,7 +1313,9 @@ TemplateSpecializationType(TemplateName T,
     if (Args[Arg].getKind() == TemplateArgument::Type &&
         Args[Arg].getAsType()->isVariablyModifiedType())
       setVariablyModified();
-    
+    if (Args[Arg].containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack();
+
     new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
   }
 }
index dbf9b6dad4f666ea4f0d3e217b6e16bedccde1a7..403838176c63a7c7e4fca1e8fbbc52df56bba09f 100644 (file)
@@ -2414,6 +2414,10 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
   TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
   QualType R = TInfo->getType();
 
+  if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+                                      UPPC_DeclarationType))
+    D.setInvalidType();
+
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
                         ForRedeclaration);
 
index 4fc770eecfb95f925eb1e10b5ccf2ab2262e13db..3cfde26d24b0829f9917191c991a381334cda788 100644 (file)
@@ -543,6 +543,11 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
 
   TypeSourceInfo *TInfo = 0;
   GetTypeFromParser(basetype, &TInfo);
+
+  if (DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, 
+                                      UPPC_BaseType))
+    return true;
+
   if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
                                                       Virtual, Access, TInfo))
     return BaseSpec;
index 92441918d11efeebb2a8135e7bc94cf18fda7853..41a342942c8a688256fb98e53674cc661bafb9c2 100644 (file)
@@ -3629,6 +3629,9 @@ void Sema::IgnoredValueConversions(Expr *&E) {
 ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) {
   if (!FullExpr) return ExprError();
 
+  if (DiagnoseUnexpandedParameterPack(FullExpr))
+    return ExprError();
+
   IgnoredValueConversions(FullExpr);
   CheckImplicitConversions(FullExpr);
   return MaybeCreateExprWithCleanups(FullExpr);
index 53a02a98864cfa27b84c3a5a8b15adcdc21ae1e9..141c41618d8b9d5d110d08ac18a5ec6bd7448cef 100644 (file)
@@ -5954,3 +5954,33 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
   Result += ']';
   return Result;
 }
+
+bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, 
+                                           TypeSourceInfo *T,
+                                         UnexpandedParameterPackContext UPPC) {
+  // C++0x [temp.variadic]p5:
+  //   An appearance of a name of a parameter pack that is not expanded is 
+  //   ill-formed.
+  if (!T->getType()->containsUnexpandedParameterPack())
+    return false;
+
+  // FIXME: Provide the names and locations of the unexpanded parameter packs.
+  Diag(Loc, diag::err_unexpanded_parameter_pack)
+    << (int)UPPC << T->getTypeLoc().getSourceRange();
+  return true;
+}
+
+bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
+                                           UnexpandedParameterPackContext UPPC) {
+  // C++0x [temp.variadic]p5:
+  //   An appearance of a name of a parameter pack that is not expanded is 
+  //   ill-formed.
+  if (!E->containsUnexpandedParameterPack())
+    return false;
+
+  // FIXME: Provide the names and locations of the unexpanded parameter packs.
+  Diag(E->getSourceRange().getBegin(), diag::err_unexpanded_parameter_pack)
+    << (int)UPPC << E->getSourceRange();
+  return true;
+}
+
index 353477d96340a8ed93ae6682092d996d2da7946b..aa669b34b3d1f4ce8c22ce688f42b16cf80c171b 100644 (file)
@@ -59,7 +59,7 @@ namespace clang {
 
     /// \brief The number of record fields required for the Expr class
     /// itself.
-    static const unsigned NumExprFields = NumStmtFields + 5;
+    static const unsigned NumExprFields = NumStmtFields + 6;
     
     /// \brief Read and initialize a ExplicitTemplateArgumentList structure.
     void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
@@ -399,6 +399,7 @@ void ASTStmtReader::VisitExpr(Expr *E) {
   E->setType(Reader.GetType(Record[Idx++]));
   E->setTypeDependent(Record[Idx++]);
   E->setValueDependent(Record[Idx++]);
+  E->ExprBits.ContainsUnexpandedParameterPack = Record[Idx++];
   E->setValueKind(static_cast<ExprValueKind>(Record[Idx++]));
   E->setObjectKind(static_cast<ExprObjectKind>(Record[Idx++]));
   assert(Idx == NumExprFields && "Incorrect expression field count");
index 35b096e65594f757cd793d57ba2936721b6fcc78..89c293fe6caaf988da7a75a177f38f68c5bf2012 100644 (file)
@@ -359,6 +359,7 @@ void ASTStmtWriter::VisitExpr(Expr *E) {
   Writer.AddTypeRef(E->getType(), Record);
   Record.push_back(E->isTypeDependent());
   Record.push_back(E->isValueDependent());
+  Record.push_back(E->containsUnexpandedParameterPack());
   Record.push_back(E->getValueKind());
   Record.push_back(E->getObjectKind());
 }
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
new file mode 100644 (file)
index 0000000..20a02e3
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+
+// An appearance of a name of a parameter pack that is not expanded is
+// ill-formed.
+template<typename ... Types>
+struct TestPPName 
+  : public Types  // expected-error{{base type contains unexpanded parameter pack}}
+{
+  typedef Types *types_pointer; // expected-error{{declaration type contains unexpanded parameter pack}}
+};