]> granicus.if.org Git - clang/commitdiff
Add an AST representation for non-type template parameter
authorDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 23:51:58 +0000 (23:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 23:51:58 +0000 (23:51 +0000)
packs, e.g.,

  template<typename T, unsigned ...Dims> struct multi_array;

along with semantic analysis support for finding unexpanded non-type
template parameter packs in types, expressions, and so on.

Template instantiation involving non-type template parameter packs
probably doesn't work yet. That'll come soon.

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

18 files changed:
include/clang/AST/DeclTemplate.h
include/clang/AST/Expr.h
include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/ASTContext.cpp
lib/AST/ASTImporter.cpp
lib/AST/DeclBase.cpp
lib/AST/DeclTemplate.cpp
lib/AST/Expr.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaTemplateVariadic.cpp
lib/Sema/SemaType.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
test/CXX/temp/temp.decls/temp.variadic/p5.cpp

index 7a311c874160f41b56a4c1a731bfdb5772b1e076..f2f91786bce34a8de1d165df009050adadc1d3ec 100644 (file)
@@ -990,17 +990,27 @@ class NonTypeTemplateParmDecl
   /// it was inherited.
   llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited;
 
+  // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
+  // down here to save memory.
+    
+  /// \brief Whether this non-type template parameter is a parameter pack.
+  bool ParameterPack;
+    
   NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
                           unsigned P, IdentifierInfo *Id, QualType T,
-                          TypeSourceInfo *TInfo)
+                          bool ParameterPack, TypeSourceInfo *TInfo)
     : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None),
-      TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false)
+      TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
+      ParameterPack(ParameterPack)
   { }
 
+  friend class ASTDeclReader;
+    
 public:
   static NonTypeTemplateParmDecl *
   Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
-         unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo);
+         unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, 
+         TypeSourceInfo *TInfo);
 
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::setDepth;
@@ -1042,6 +1052,17 @@ public:
     DefaultArgumentAndInherited.setInt(false);
   }
 
+  /// \brief Whether this parameter is a non-type template parameter pack.
+  ///
+  /// If the parameter is a parameter pack, the type may be a
+  /// \c PackExpansionType. In the following example, the \c Dims parameter
+  /// is a parameter pack (whose type is 'unsigned').
+  ///
+  /// \code
+  /// template<typename T, unsigned ...Dims> struct multi_array;
+  /// \endcode
+  bool isParameterPack() const { return ParameterPack; }
+    
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
index e12f45b49ee51691338634b40a603d9c19465caa..d2add78cd8dce0f6890e5c210713b9847de7e817 100644 (file)
@@ -3564,6 +3564,7 @@ class BlockDeclRefExpr : public Expr {
   Stmt *CopyConstructorVal;
 public:
   // FIXME: Fix type/value dependence!
+  // FIXME: Variadic templates.
   BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
                    SourceLocation l, bool ByRef, bool constAdded = false,
                    Stmt *copyConstructorVal = 0)
index 98ea9d4bd6d9f5cf0e379b0fcb8bea39fc5d5923..1374402012dd97eda383a245f63b657ff486ac73 100644 (file)
@@ -47,6 +47,8 @@ def err_param_redefinition : Error<"redefinition of parameter %0">;
 def err_invalid_storage_class_in_func_decl : Error<
   "invalid storage class specifier in function declarator">;
 def err_expected_namespace_name : Error<"expected namespace name">;
+def err_variadic_templates : Error<
+  "variadic templates are only allowed in C++0x">;
 
 // Sema && Lex
 def ext_longlong : Extension<
index 3d677abb429b6c5d6f2677f3a052a02e18c48217..e8eb111795903ee10cc6a2e68753b2a873982728 100644 (file)
@@ -374,9 +374,6 @@ def err_expected_type_name_after_typename : Error<
 def err_explicit_spec_non_template : Error<
   "explicit %select{specialization|instantiation}0 of non-template "
   "%select{class|struct|union}1 %2">;
-
-def err_variadic_templates : Error<
-  "variadic templates are only allowed in C++0x">;
   
 def err_default_template_template_parameter_not_template : Error<
   "default template argument for a template template parameter must be a class "
index 8e7a2ba818d4c1d9da565011187b87f02cb0cc2e..49c9c4b6b700cf980779a2d7767a9103ef5c861c 100644 (file)
@@ -1876,8 +1876,6 @@ def err_pack_expansion_mismatch_unsupported : Error<
   "clang cannot yet instantiate pack expansions with mismatched pack levels">;
 def err_function_parameter_pack_unsupported : Error<
   "clang does not yet support function parameter packs">;
-def err_non_type_parameter_pack_unsupported : Error<
-  "clang does not yet support non-type template parameter packs">;
 
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
index e20b1ed63fe3e0e1a92bb9af8076a86da905f2c3..eaf222cafad80e70b5b2a4e4b584db0bc291291a 100644 (file)
@@ -109,6 +109,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
                                             SourceLocation(), NTTP->getDepth(),
                                             NTTP->getPosition(), 0, 
                                             getCanonicalType(NTTP->getType()),
+                                            NTTP->isParameterPack(),
                                             0));
     else
       CanonParams.push_back(getCanonicalTemplateTemplateParmDecl(
index 7ff217e3345cc48f0e2105dec9dfa1f265ab2290..7d6c90519b9ff10eda5af2d62a68e8b6367d9d82 100644 (file)
@@ -3414,7 +3414,7 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
                                Importer.getToContext().getTranslationUnitDecl(),
                                          Loc, D->getDepth(), D->getPosition(),
                                          Name.getAsIdentifierInfo(),
-                                         T, TInfo);
+                                         T, D->isParameterPack(), TInfo);
 }
 
 Decl *
index 843e907dea9aad1ea6fc0cb2b495c4dc0f2adcc0..75ea2df27e0d7e3dc113ee509e11b56b2c87bfe0 100644 (file)
@@ -110,7 +110,9 @@ void Decl::add(Kind k) {
 bool Decl::isTemplateParameterPack() const {
   if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
     return TTP->isParameterPack();
-
+  if (const NonTypeTemplateParmDecl *NTTP
+                                = llvm::dyn_cast<NonTypeTemplateParmDecl>(this))
+    return NTTP->isParameterPack();
   return false;
 }
 
index 422e5e30f8bf259f4a3d545caa71c36f8512cad5..dff956c6dceb40cb94d6b9aff18ea7c561862d9f 100644 (file)
@@ -390,8 +390,9 @@ NonTypeTemplateParmDecl *
 NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
                                 SourceLocation L, unsigned D, unsigned P,
                                 IdentifierInfo *Id, QualType T,
-                                TypeSourceInfo *TInfo) {
-  return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo);
+                                bool ParameterPack, TypeSourceInfo *TInfo) {
+  return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack,
+                                         TInfo);
 }
 
 SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
index 5d0e0e309332b8035d4874ef299ec55a5a40eb23..d8bb0af01838b238a0ec485ac410c9e7607a9523 100644 (file)
@@ -208,8 +208,14 @@ void DeclRefExpr::computeDependence() {
   //          member of an unknown specialization.
   //        (handled by DependentScopeDeclRefExpr)
 
-  // FIXME: Variadic templates require that we compute whether this
-  // declaration reference contains an unexpanded parameter pack.
+  // Determine whether this expression contains any unexpanded parameter
+  // packs.
+  // Is the declaration a parameter pack?
+  if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+    if (NTTP->isParameterPack())
+      ExprBits.ContainsUnexpandedParameterPack = true;
+  }
+  // FIXME: Variadic templates function parameter packs.
 }
 
 DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, 
index 7357e9449069477e1e565d0c137a066ae3698c11..a487825bb37c710576cb6411d7ebbc0f4cca49bc 100644 (file)
@@ -632,16 +632,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
     Invalid = true;
   }
   
-  if (D.hasEllipsis()) {
-    // FIXME: Variadic templates.
-    Diag(D.getEllipsisLoc(), diag::err_non_type_parameter_pack_unsupported);
-    Invalid = true;
-  }
-      
+  bool IsParameterPack = D.hasEllipsis();
   NonTypeTemplateParmDecl *Param
     = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
                                       D.getIdentifierLoc(),
-                                      Depth, Position, ParamName, T, TInfo);
+                                      Depth, Position, ParamName, T, 
+                                      IsParameterPack, TInfo);
   if (Invalid)
     Param->setInvalidDecl();
 
@@ -652,7 +648,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
   }
   
   // Check the well-formedness of the default template argument, if provided.
-  if (Default) {  
+  if (Default) {
     // Check for unexpanded parameter packs.
     if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
       return Param;
index 54c509544f7b5d061a9d5ca7ccd42a4509b879ff..9db3a8cacfe5535388a30653d3521dfc15220a59 100644 (file)
@@ -1506,11 +1506,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
     Invalid = true;
   }
   
+  // FIXME: Variadic templates.
   NonTypeTemplateParmDecl *Param
     = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
                                     D->getDepth() - TemplateArgs.getNumLevels(), 
                                       D->getPosition(), D->getIdentifier(), T, 
-                                      DI);
+                                      D->isParameterPack(), DI);
   if (Invalid)
     Param->setInvalidDecl();
   
index d9c7e72a867b6e65afb85bebce42bf0a62eedf07..fe30ba5845f1f13ff4e25e4c4f38aa1022c278b4 100644 (file)
@@ -63,8 +63,21 @@ namespace {
       return true;
     }
 
-    // FIXME: Record occurrences of non-type and template template
-    // parameter packs.
+    /// \brief Record occurrences of (FIXME: function and) non-type template
+    /// parameter packs in an expression.
+    bool VisitDeclRefExpr(DeclRefExpr *E) {
+      if (NonTypeTemplateParmDecl *NTTP 
+                            = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
+        if (NTTP->isParameterPack())
+          Unexpanded.push_back(std::make_pair(NTTP, E->getLocation()));
+      }
+      
+      // FIXME: Function parameter packs.
+      
+      return true;
+    }
+    
+    // FIXME: Record occurrences of template template parameter packs.
 
     // FIXME: Once we have pack expansions in the AST, block their
     // traversal.
@@ -95,8 +108,8 @@ namespace {
     /// \brief Suppress traversel into types with location information
     /// that do not contain unexpanded parameter packs.
     bool TraverseTypeLoc(TypeLoc TL) {
-      if (!TL.getType().isNull() && TL.
-          getType()->containsUnexpandedParameterPack())
+      if (!TL.getType().isNull() && 
+          TL.getType()->containsUnexpandedParameterPack())
         return inherited::TraverseTypeLoc(TL);
 
       return true;
index e693c8d4daa04791148402824185453104088f19..46ec0fe10914dd004c9bee56b6c852559bfd312a 100644 (file)
@@ -1504,6 +1504,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
       // it expands those parameter packs.
       if (T->containsUnexpandedParameterPack())
         T = Context.getPackExpansionType(T);
+      else if (!getLangOptions().CPlusPlus0x)
+        Diag(D.getEllipsisLoc(), diag::err_variadic_templates);
       break;
     
     case Declarator::FileContext:
index 6100d65757cc7ca7bee0aabd4e0f97e2b83be828..f2183ea695f84c8e30b6c2d7bbaccc41efd4abf0 100644 (file)
@@ -1156,6 +1156,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
   D->setDepth(Record[Idx++]);
   D->setPosition(Record[Idx++]);
   // Rest of NonTypeTemplateParmDecl.
+  D->ParameterPack = Record[Idx++];
   if (Record[Idx++]) {
     Expr *DefArg = Reader.ReadExpr(F);
     bool Inherited = Record[Idx++];
@@ -1429,7 +1430,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
     break;
   case DECL_NON_TYPE_TEMPLATE_PARM:
     D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0,
-                                        QualType(),0);
+                                        QualType(), false, 0);
     break;
   case DECL_TEMPLATE_TEMPLATE_PARM:
     D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0);
index aa145c415bca623db99e1749cd016857479ae58a..add6cd343da585c83eb1e04c5556508256931796 100644 (file)
@@ -994,6 +994,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
   Record.push_back(D->getDepth());
   Record.push_back(D->getPosition());
   // Rest of NonTypeTemplateParmDecl.
+  Record.push_back(D->isParameterPack());
   Record.push_back(D->getDefaultArgument() != 0);
   if (D->getDefaultArgument()) {
     Writer.AddStmt(D->getDefaultArgument());
index 59a0e7538d993d37100ac27814fcdad85590566a..d6df2370ad99d330fd6336115deb58167c5177d1 100644 (file)
@@ -11,12 +11,12 @@ void f1(const Types &...args); // FIXME: temporary expected-error{{clang does no
 // [ Note: Otherwise, the parameter-declaration is part of a
 // template-parameter-list and the parameter pack is a template
 // parameter pack; see 14.1. -- end note ]
-template<int ...N> // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+template<int ...N>
 struct X0 { };
 
 template<typename ...Types>
 struct X1 {
-  template<Types ...Values> struct Inner; // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+  template<Types ...Values> struct Inner;
 };
 
 // A declarator-id or abstract-declarator containing an ellipsis shall
index aff9b44539f698c3cb25d77a724d030ca18e724f..47581fee90a48c0e50fac11b17fe72a6493503be 100644 (file)
@@ -128,6 +128,26 @@ struct TestPPName
 };
 
 // FIXME: Test for unexpanded parameter packs in each of the expression nodes.
+template<int ...Values>
+void test_unexpanded_in_exprs() {
+  // PredefinedExpr is uninteresting
+  // DeclRefExpr
+  Values; // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+  // IntegerLiteral is uninteresting
+  // FloatingLiteral is uninteresting
+  // ImaginaryLiteral is uninteresting
+  // StringLiteral is uninteresting
+  // CharacterLiteral is uninteresting
+  (Values); // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+  // UnaryOperator
+  -Values; // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+  // OffsetOfExpr
+  struct OffsetMe {
+    int array[17];
+  };
+  __builtin_offsetof(OffsetMe, array[Values]); // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+  // FIXME: continue this...
+}
 
 template<typename ... Types>
 void TestPPNameFunc(int i) {