]> granicus.if.org Git - clang/commitdiff
Implement parsing, semantic analysis and ASTs for default template
authorDouglas Gregor <dgregor@apple.com>
Tue, 10 Feb 2009 19:49:53 +0000 (19:49 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 10 Feb 2009 19:49:53 +0000 (19:49 +0000)
arguments. This commit covers checking and merging default template
arguments from previous declarations, but it does not cover the actual
use of default template arguments when naming class template
specializations.

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

include/clang/AST/DeclTemplate.h
include/clang/Basic/DiagnosticSemaKinds.def
include/clang/Parse/Action.h
lib/AST/DeclTemplate.cpp
lib/Parse/ParseTemplate.cpp
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
test/Parser/cxx-template-decl.cpp
test/SemaTemplate/temp_param.cpp

index b466a118b17582d4d8b946abece7fbd8bb9ff2a1..ccbe1288f84af4ce7bc3b1319f6e28551a00ef1c 100644 (file)
@@ -225,9 +225,20 @@ class TemplateTypeParmDecl : public TypeDecl {
   /// 'class' keyword.
   bool Typename : 1;
 
+  /// \brief Whether this template type parameter inherited its
+  /// default argument.
+  bool InheritedDefault : 1;
+
+  /// \brief The location of the default argument, if any.
+  SourceLocation DefaultArgumentLoc;
+
+  /// \brief The default template argument, if any.
+  QualType DefaultArgument;
+
   TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, 
                        bool Typename, QualType Type)
-    : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename) { 
+    : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
+      InheritedDefault(false), DefaultArgument() { 
     TypeForDecl = Type.getTypePtr();
   }
 
@@ -241,6 +252,30 @@ public:
   /// keyword.
   bool wasDeclaredWithTypename() const { return Typename; }
 
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
+
+  /// \brief Retrieve the default argument, if any.
+  QualType getDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
+
+  /// \brief Determines whether the default argument was inherited
+  /// from a previous declaration of this template.
+  bool defaultArgumentWasInherited() const { return InheritedDefault; }
+
+  /// \brief Set the default argument for this template parameter, and
+  /// whether that default argument was inherited from another
+  /// declaration.
+  void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
+                          bool Inherited) {
+    DefaultArgument = DefArg;
+    DefaultArgumentLoc = DefArgLoc;
+    InheritedDefault = Inherited;
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
     return D->getKind() == TemplateTypeParm;
@@ -264,11 +299,16 @@ protected:
 /// @endcode
 class NonTypeTemplateParmDecl
   : public VarDecl, protected TemplateParmPosition {
+  /// \brief The default template argument, if any.
+  Expr *DefaultArgument;
+
   NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
                           unsigned P, IdentifierInfo *Id, QualType T,
                           SourceLocation TSSL = SourceLocation())
     : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
-      TemplateParmPosition(D, P) { }
+      TemplateParmPosition(D, P), DefaultArgument(0) 
+  { }
+
 public:
   static NonTypeTemplateParmDecl *
   Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
@@ -278,6 +318,21 @@ public:
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::getPosition;
 
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the default argument, if any.
+  Expr *getDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const;
+
+  /// \brief Set the default argument for this template parameter.
+  void setDefaultArgument(Expr *DefArg) {
+    DefaultArgument = DefArg;
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
     return D->getKind() == NonTypeTemplateParm;
@@ -304,12 +359,17 @@ protected:
 /// name of a template and the template parameters allowable for substitution.
 class TemplateTemplateParmDecl
   : public TemplateDecl, protected TemplateParmPosition {
+
+  /// \brief The default template argument, if any.
+  Expr *DefaultArgument;
+
   TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
                            unsigned D, unsigned P,
                            IdentifierInfo *Id, TemplateParameterList *Params)
     : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
-      TemplateParmPosition(D, P)
+      TemplateParmPosition(D, P), DefaultArgument(0)
     { }
+
 public:
   static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
                                           SourceLocation L, unsigned D,
@@ -319,6 +379,21 @@ public:
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::getPosition;
 
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the default argument, if any.
+  Expr *getDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const;
+
+  /// \brief Set the default argument for this template parameter.
+  void setDefaultArgument(Expr *DefArg) {
+    DefaultArgument = DefArg;
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
     return D->getKind() == TemplateTemplateParm;
index 9fad3af483f46756e748858235585902ca6e6336..9c879f740aa263b5a9efe0e80ca4c744061fffe0 100644 (file)
@@ -495,6 +495,12 @@ DIAG(note_template_nontype_parm_prev_declaration, NOTE,
      "previous non-type template parameter with type %0 is here")
 DIAG(err_template_nontype_parm_bad_type, ERROR,
      "a non-type template parameter cannot have type %0")
+DIAG(err_template_param_default_arg_redefinition, ERROR,
+     "template parameter redefines default argument")
+DIAG(note_template_param_prev_default_arg, NOTE,
+     "previous default template argument defined here")
+DIAG(err_template_param_default_arg_missing, ERROR,
+     "template parameter missing a default argument")
 
 // C++ Template Argument Lists
 DIAG(err_template_arg_list_different_arity, ERROR,
index efa94a2dc7db74a30274f96be2b995e34c52c7aa..3c2ecfb0ebd8af2b3b8b92cc2799083f850ec628 100644 (file)
@@ -1040,7 +1040,10 @@ public:
 
   /// ActOnTypeParameterDefault - Adds a default argument (the type
   /// Default) to the given template type parameter (TypeParam). 
-  virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, TypeTy *Default) {
+  virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, 
+                                         SourceLocation EqualLoc,
+                                         SourceLocation DefaultLoc,
+                                         TypeTy *Default) {
   }
 
   /// ActOnNonTypeTemplateParameter - Called when a C++ non-type
@@ -1056,6 +1059,13 @@ public:
     return 0;
   }
 
+  /// \brief Adds a default argument to the given non-type template
+  /// parameter.
+  virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam,
+                                                    SourceLocation EqualLoc,
+                                                    ExprArg Default) {
+  }
+
   /// ActOnTemplateTemplateParameter - Called when a C++ template template
   /// parameter (e.g., "int T" in "template<template <typename> class T> class
   /// Array") has been parsed. TmpLoc is the location of the "template" keyword,
@@ -1072,6 +1082,13 @@ public:
     return 0;
   }
 
+  /// \brief Adds a default argument to the given template template
+  /// parameter.
+  virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam,
+                                                     SourceLocation EqualLoc,
+                                                     ExprArg Default) {
+  }
+
   /// ActOnTemplateParameterList - Called when a complete template
   /// parameter list has been parsed, e.g.,
   ///
index 4eb866d6887b7e6a50d7fca42eed0cce59e26299..b297dd25cbe42c5dcd841b8435d4bd1d54a3ad2f 100644 (file)
@@ -102,6 +102,11 @@ NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
                                          TypeSpecStartLoc);
 }
 
+SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
+  return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+                        : SourceLocation(); 
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateTemplateParmDecl Method Implementations
 //===----------------------------------------------------------------------===//
@@ -114,3 +119,7 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
   return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
 }
 
+SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
+  return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+                        : SourceLocation(); 
+}
index 25aea352242a337106956862fc1121322cccec16..d17d2445351a9d866775a734c19d8947948f5ce2 100644 (file)
@@ -228,8 +228,10 @@ Parser::DeclTy *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
   // Grab a default type id (if given).
   if(Tok.is(tok::equal)) {
     SourceLocation EqualLoc = ConsumeToken();
+    SourceLocation DefaultLoc = Tok.getLocation();
     if (TypeTy *DefaultType = ParseTypeName())
-      Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
+      Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
+                                        DefaultType);
   }
   
   return TypeParam;
@@ -277,18 +279,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
     return 0;
   }
 
-  // Get the a default value, if given.
-  // FIXME: I think that the results of this block need to be passed to the
-  // act-on call, so we can assemble the parameter correctly.
-  OwningExprResult DefaultExpr(Actions);
-  if(Tok.is(tok::equal)) {
-    ConsumeToken();
-    DefaultExpr = ParseCXXIdExpression();
-    if(DefaultExpr.isInvalid()) {
-      return 0;
-    }
-  }
-
   TemplateParamsTy *ParamList = 
     Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
                                        TemplateLoc, LAngleLoc,
@@ -296,9 +286,23 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
                                        TemplateParams.size(),
                                        RAngleLoc);
 
-  return Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
-                                                ParamList, ParamName,
-                                                NameLoc, Depth, Position);
+  Parser::DeclTy * Param
+    = Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
+                                             ParamList, ParamName,
+                                             NameLoc, Depth, Position);
+
+  // Get the a default value, if given.
+  if (Tok.is(tok::equal)) {
+    SourceLocation EqualLoc = ConsumeToken();
+    OwningExprResult DefaultExpr = ParseCXXIdExpression();
+    if (DefaultExpr.isInvalid())
+      return Param;
+    else if (Param)
+      Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc,
+                                                    move(DefaultExpr));
+  }
+
+  return Param;
 }
 
 /// ParseNonTypeTemplateParameter - Handle the parsing of non-type
@@ -341,12 +345,23 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
   DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
                                                         Depth, Position);
 
-  // Is there a default value? Parsing this can be fairly annoying because
-  // we have to stop on the first non-nested (paren'd) '>' as the closure
-  // for the template parameter list. Or a ','.
+  // If there is a default value, parse it.
   if (Tok.is(tok::equal)) {
-    // TODO: Implement default non-type values.
-    SkipUntil(tok::comma, tok::greater, true, true);
+    SourceLocation EqualLoc = ConsumeToken();
+
+    // C++ [temp.param]p15:
+    //   When parsing a default template-argument for a non-type
+    //   template-parameter, the first non-nested > is taken as the
+    //   end of the template-parameter-list rather than a greater-than
+    //   operator.
+    GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);   
+
+    OwningExprResult DefaultArg = ParseAssignmentExpression();
+    if (DefaultArg.isInvalid())
+      SkipUntil(tok::comma, tok::greater, true, true);
+    else if (Param)
+      Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc, 
+                                                   move(DefaultArg));
   }
   
   return Param;
index e3d132efbbd80d8c65dbe84a636a3cbb826efe56..669fd9258408b2ca14c821dc22c7221576e96929 100644 (file)
@@ -1490,9 +1490,17 @@ public:
                                      IdentifierInfo *ParamName,
                                      SourceLocation ParamNameLoc,
                                      unsigned Depth, unsigned Position);
+  virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, 
+                                         SourceLocation EqualLoc,
+                                         SourceLocation DefaultLoc,
+                                         TypeTy *Default);
+
   virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
                                                 unsigned Depth,
                                                 unsigned Position);
+  virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam,
+                                                    SourceLocation EqualLoc,
+                                                    ExprArg Default);
   virtual DeclTy *ActOnTemplateTemplateParameter(Scope *S,
                                                  SourceLocation TmpLoc,
                                                  TemplateParamsTy *Params,
@@ -1500,6 +1508,10 @@ public:
                                                  SourceLocation ParamNameLoc,
                                                  unsigned Depth,
                                                  unsigned Position);
+  virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam,
+                                                     SourceLocation EqualLoc,
+                                                     ExprArg Default);
+
   virtual TemplateParamsTy *
   ActOnTemplateParameterList(unsigned Depth,
                              SourceLocation ExportLoc,
@@ -1507,7 +1519,9 @@ public:
                              SourceLocation LAngleLoc,
                              DeclTy **Params, unsigned NumParams,
                              SourceLocation RAngleLoc);
-  
+  bool CheckTemplateParameterList(TemplateParameterList *NewParams,
+                                  TemplateParameterList *OldParams);
+
   virtual DeclTy *
   ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
                      SourceLocation KWLoc, const CXXScopeSpec &SS,
index c0c6e23baf6705a525326e44abdd868d380fec29..5eb2b2145c96dedbf9dea680eb300b2d5a3081bc 100644 (file)
@@ -140,6 +140,29 @@ Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename,
   return Param;
 }
 
+/// ActOnTypeParameterDefault - Adds a default argument (the type
+/// Default) to the given template type parameter (TypeParam). 
+void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam, 
+                                     SourceLocation EqualLoc,
+                                     SourceLocation DefaultLoc, 
+                                     TypeTy *DefaultT) {
+  TemplateTypeParmDecl *Parm 
+    = cast<TemplateTypeParmDecl>(static_cast<Decl *>(TypeParam));
+  QualType Default = QualType::getFromOpaquePtr(DefaultT);
+
+  // C++ [temp.param]p14:
+  //   A template-parameter shall not be used in its own default argument.
+  // FIXME: Implement this check! Needs a recursive walk over the types.
+  
+  // Check the template argument itself.
+  if (CheckTemplateArgument(Parm, Default, DefaultLoc)) {
+    Parm->setInvalidDecl();
+    return;
+  }
+
+  Parm->setDefaultArgument(Default, DefaultLoc, false);
+}
+
 /// ActOnNonTypeTemplateParameter - Called when a C++ non-type
 /// template parameter (e.g., "int Size" in "template<int Size>
 /// class Array") has been parsed. S is the current scope and D is
@@ -210,6 +233,28 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
   return Param;
 }
 
+/// \brief Adds a default argument to the given non-type template
+/// parameter.
+void Sema::ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParamD,
+                                                SourceLocation EqualLoc,
+                                                ExprArg DefaultE) {
+  NonTypeTemplateParmDecl *TemplateParm 
+    = cast<NonTypeTemplateParmDecl>(static_cast<Decl *>(TemplateParamD));
+  Expr *Default = static_cast<Expr *>(DefaultE.get());
+  
+  // C++ [temp.param]p14:
+  //   A template-parameter shall not be used in its own default argument.
+  // FIXME: Implement this check! Needs a recursive walk over the types.
+  
+  // Check the well-formedness of the default template argument.
+  if (CheckTemplateArgument(TemplateParm, Default)) {
+    TemplateParm->setInvalidDecl();
+    return;
+  }
+
+  TemplateParm->setDefaultArgument(static_cast<Expr *>(DefaultE.release()));
+}
+
 
 /// ActOnTemplateTemplateParameter - Called when a C++ template template
 /// parameter (e.g. T in template <template <typename> class T> class array)
@@ -250,6 +295,40 @@ Sema::DeclTy *Sema::ActOnTemplateTemplateParameter(Scope* S,
   return Param;
 }
 
+/// \brief Adds a default argument to the given template template
+/// parameter.
+void Sema::ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParamD,
+                                                 SourceLocation EqualLoc,
+                                                 ExprArg DefaultE) {
+  TemplateTemplateParmDecl *TemplateParm 
+    = cast<TemplateTemplateParmDecl>(static_cast<Decl *>(TemplateParamD));
+
+  // Since a template-template parameter's default argument is an
+  // id-expression, it must be a DeclRefExpr.
+  DeclRefExpr *Default 
+    = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
+
+  // C++ [temp.param]p14:
+  //   A template-parameter shall not be used in its own default argument.
+  // FIXME: Implement this check! Needs a recursive walk over the types.
+
+  // Check the well-formedness of the template argument.
+  if (!isa<TemplateDecl>(Default->getDecl())) {
+    Diag(Default->getSourceRange().getBegin(), 
+         diag::err_template_arg_must_be_template)
+      << Default->getSourceRange();
+    TemplateParm->setInvalidDecl();
+    return;
+  } 
+  if (CheckTemplateArgument(TemplateParm, Default)) {
+    TemplateParm->setInvalidDecl();
+    return;
+  }
+
+  DefaultE.release();
+  TemplateParm->setDefaultArgument(Default);
+}
+
 /// ActOnTemplateParameterList - Builds a TemplateParameterList that
 /// contains the template parameters in Params/NumParams.
 Sema::TemplateParamsTy *
@@ -274,6 +353,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
                          MultiTemplateParamsArg TemplateParameterLists) {
   assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
   assert(TK != TK_Reference && "Can only declare or define class templates");
+  bool Invalid = false;
 
   // Check that we can declare a template here.
   if (CheckTemplateDeclScope(S, TemplateParameterLists))
@@ -363,6 +443,13 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
     return 0;
   }
 
+  // Check the template parameter list of this declaration, possibly
+  // merging in the template parameter list from the previous class
+  // template declaration.
+  if (CheckTemplateParameterList(TemplateParams,
+            PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
+    Invalid = true;
+    
   // If we had a scope specifier, we better have a previous template
   // declaration!
 
@@ -388,10 +475,171 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
 
   PushOnScopeChains(NewTemplate, S);
 
+  if (Invalid) {
+    NewTemplate->setInvalidDecl();
+    NewClass->setInvalidDecl();
+  }
   return NewTemplate;
 }
 
+/// \brief Checks the validity of a template parameter list, possibly
+/// considering the template parameter list from a previous
+/// declaration.
+///
+/// If an "old" template parameter list is provided, it must be
+/// equivalent (per TemplateParameterListsAreEqual) to the "new"
+/// template parameter list.
+///
+/// \param NewParams Template parameter list for a new template
+/// declaration. This template parameter list will be updated with any
+/// default arguments that are carried through from the previous
+/// template parameter list.
+///
+/// \param OldParams If provided, template parameter list from a
+/// previous declaration of the same template. Default template
+/// arguments will be merged from the old template parameter list to
+/// the new template parameter list.
+///
+/// \returns true if an error occurred, false otherwise.
+bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
+                                      TemplateParameterList *OldParams) {
+  bool Invalid = false;
+  
+  // C++ [temp.param]p10:
+  //   The set of default template-arguments available for use with a
+  //   template declaration or definition is obtained by merging the
+  //   default arguments from the definition (if in scope) and all
+  //   declarations in scope in the same way default function
+  //   arguments are (8.3.6).
+  bool SawDefaultArgument = false;
+  SourceLocation PreviousDefaultArgLoc;
+
+  TemplateParameterList::iterator OldParam;
+  if (OldParams)
+    OldParam = OldParams->begin();
+
+  for (TemplateParameterList::iterator NewParam = NewParams->begin(),
+                                    NewParamEnd = NewParams->end();
+       NewParam != NewParamEnd; ++NewParam) {
+    // Variables used to diagnose redundant default arguments
+    bool RedundantDefaultArg = false;
+    SourceLocation OldDefaultLoc;
+    SourceLocation NewDefaultLoc;
+
+    // Variables used to diagnose missing default arguments
+    bool MissingDefaultArg = false;
+
+    // Merge default arguments for template type parameters.
+    if (TemplateTypeParmDecl *NewTypeParm
+          = dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
+      TemplateTypeParmDecl *OldTypeParm 
+          = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
+      
+      if (OldTypeParm && OldTypeParm->hasDefaultArgument() && 
+          NewTypeParm->hasDefaultArgument()) {
+        OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
+        NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
+        SawDefaultArgument = true;
+        RedundantDefaultArg = true;
+        PreviousDefaultArgLoc = NewDefaultLoc;
+      } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
+        // Merge the default argument from the old declaration to the
+        // new declaration.
+        SawDefaultArgument = true;
+        NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(),
+                                        OldTypeParm->getDefaultArgumentLoc(),
+                                        true);
+        PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc();
+      } else if (NewTypeParm->hasDefaultArgument()) {
+        SawDefaultArgument = true;
+        PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc();
+      } else if (SawDefaultArgument)
+        MissingDefaultArg = true;
+    } 
+    // Merge default arguments for non-type template parameters
+    else if (NonTypeTemplateParmDecl *NewNonTypeParm
+               = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+      NonTypeTemplateParmDecl *OldNonTypeParm
+        = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
+      if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && 
+          NewNonTypeParm->hasDefaultArgument()) {
+        OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
+        NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
+        SawDefaultArgument = true;
+        RedundantDefaultArg = true;
+        PreviousDefaultArgLoc = NewDefaultLoc;
+      } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
+        // Merge the default argument from the old declaration to the
+        // new declaration.
+        SawDefaultArgument = true;
+        // FIXME: We need to create a new kind of "default argument"
+        // expression that points to a previous template template
+        // parameter.
+        NewNonTypeParm->setDefaultArgument(
+                                        OldNonTypeParm->getDefaultArgument());
+        PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc();
+      } else if (NewNonTypeParm->hasDefaultArgument()) {
+        SawDefaultArgument = true;
+        PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc();
+      } else if (SawDefaultArgument)
+        MissingDefaultArg = true;      
+    }
+    // Merge default arguments for template template parameters
+    else {
+      TemplateTemplateParmDecl *NewTemplateParm
+        = cast<TemplateTemplateParmDecl>(*NewParam);
+      TemplateTemplateParmDecl *OldTemplateParm
+        = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
+      if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && 
+          NewTemplateParm->hasDefaultArgument()) {
+        OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
+        NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
+        SawDefaultArgument = true;
+        RedundantDefaultArg = true;
+        PreviousDefaultArgLoc = NewDefaultLoc;
+      } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
+        // Merge the default argument from the old declaration to the
+        // new declaration.
+        SawDefaultArgument = true;
+        // FIXME: We need to create a new kind of "default argument"
+        // expression that points to a previous template template
+        // parameter.
+        NewTemplateParm->setDefaultArgument(
+                                        OldTemplateParm->getDefaultArgument());
+        PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc();
+      } else if (NewTemplateParm->hasDefaultArgument()) {
+        SawDefaultArgument = true;
+        PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
+      } else if (SawDefaultArgument)
+        MissingDefaultArg = true;      
+    }
+
+    if (RedundantDefaultArg) {
+      // C++ [temp.param]p12:
+      //   A template-parameter shall not be given default arguments
+      //   by two different declarations in the same scope.
+      Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition);
+      Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg);
+      Invalid = true;
+    } else if (MissingDefaultArg) {
+      // C++ [temp.param]p11:
+      //   If a template-parameter has a default template-argument,
+      //   all subsequent template-parameters shall have a default
+      //   template-argument supplied.
+      Diag((*NewParam)->getLocation(), 
+           diag::err_template_param_default_arg_missing);
+      Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg);
+      Invalid = true;
+    }
 
+    // If we have an old template parameter list that we're merging
+    // in, move on to the next parameter.
+    if (OldParams)
+      ++OldParam;
+  }
+
+  return Invalid;
+}
 
 Action::TypeTy * 
 Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
index 08b05cf823ea5c24d2528467e4ac961b82a34502..54d1081b42f8e2053c71d88eb16a2e36ec160268 100644 (file)
@@ -32,8 +32,8 @@ template <typename = int> X2;
 // Forward declarations w/template template parameters
 template <template <typename> class T> class TTP1;
 template <template <typename> class> class TTP2;
-template <template <typename> class T = foo> class TTP3;
-template <template <typename> class = foo> class TTP3;
+template <template <typename> class T = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
+template <template <typename> class = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
 template <template <typename X, typename Y> class T> class TTP5;
 
 // Forward declararations with non-type params
index 57a6cdb9454225426336f68caa9918d9e85305e7..249bf9a08d5fca078f4cc6a039e01479686377f0 100644 (file)
@@ -23,5 +23,67 @@ template<float f> struct A11; // expected-error{{a non-type template parameter c
 template<int X[10]> struct A5;
 template<int f(float, double)> struct A7;
 
+// C++ [temp.param]p11:
+template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}}
+template<typename, int> struct Y2;
 
+template<class T1 = int, // expected-note{{previous default template argument defined here}}
+         class T2>  // expected-error{{template parameter missing a default argument}}
+  class B1;
 
+template<template<class> class = Y1, // expected-note{{previous default template argument defined here}}
+         template<class> class> // expected-error{{template parameter missing a default argument}}
+  class B1t;
+
+template<int N = 5,  // expected-note{{previous default template argument defined here}}
+         int M>  // expected-error{{template parameter missing a default argument}}
+  class B1n;
+
+// FIXME: spurious "shadow" warning!
+//template<template<class T> class = Y1,
+//         template<class T> class>
+//  class B1fixme;
+
+// C++ [temp.param]p10:
+template<class T1, class T2 = int> class B2; 
+template<class T1 = int, class T2> class B2;
+
+template<template<class, int> class, template<class> class = Y1> class B2t;
+template<template<class, int> class = Y2, template<class> class> class B2t;
+
+template<int N, int M = 5> class B2n;
+template<int N = 5, int M> class B2n;
+
+// C++ [temp.param]p12:
+template<class T1, 
+         class T2 = int> // expected-note{{previous default template argument defined here}}
+  class B3;
+template<class T1, typename T2> class B3;
+template<class T1, 
+         typename T2 = float> // expected-error{{template parameter redefines default argument}}
+  class B3;
+
+template<template<class, int> class, 
+         template<class> class = Y1> // expected-note{{previous default template argument defined here}}
+  class B3t;
+
+template<template<class, int> class, template<class> class> class B3t;
+
+template<template<class, int> class, 
+         template<class> class = Y1> // expected-error{{template parameter redefines default argument}}
+  class B3t;
+
+template<int N, 
+         int M = 5> // expected-note{{previous default template argument defined here}}
+  class B3n;
+
+template<int N, int M> class B3n;
+
+template<int N, 
+         int M = 7>  // expected-error{{template parameter redefines default argument}}
+  class B3n;
+
+// Check validity of default arguments
+template<template<class, int> class // expected-note{{previous template template parameter is here}}
+           = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+  class C1;