[cfe-commits] r64229 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Tue Feb 10 11:49:53 PST 2009


Author: dgregor
Date: Tue Feb 10 13:49:53 2009
New Revision: 64229

URL: http://llvm.org/viewvc/llvm-project?rev=64229&view=rev
Log:
Implement parsing, semantic analysis and ASTs for default template
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.


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

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Feb 10 13:49:53 2009
@@ -225,9 +225,20 @@
   /// '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 @@
   /// 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 @@
 /// @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 @@
   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 @@
 /// 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 @@
   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;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Tue Feb 10 13:49:53 2009
@@ -495,6 +495,12 @@
      "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,

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Feb 10 13:49:53 2009
@@ -1040,7 +1040,10 @@
 
   /// 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 @@
     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 @@
     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.,
   ///

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Tue Feb 10 13:49:53 2009
@@ -102,6 +102,11 @@
                                          TypeSpecStartLoc);
 }
 
+SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
+  return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+                        : SourceLocation(); 
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateTemplateParmDecl Method Implementations
 //===----------------------------------------------------------------------===//
@@ -114,3 +119,7 @@
   return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
 }
 
+SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
+  return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+                        : SourceLocation(); 
+}

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Feb 10 13:49:53 2009
@@ -228,8 +228,10 @@
   // 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 @@
     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 @@
                                        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 @@
   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;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Feb 10 13:49:53 2009
@@ -1490,9 +1490,17 @@
                                      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 @@
                                                  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 @@
                              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,

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 10 13:49:53 2009
@@ -140,6 +140,29 @@
   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 @@
   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 @@
   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 @@
                          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 @@
     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 @@
 
   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,

Modified: cfe/trunk/test/Parser/cxx-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Tue Feb 10 13:49:53 2009
@@ -32,8 +32,8 @@
 // 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

Modified: cfe/trunk/test/SemaTemplate/temp_param.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_param.cpp?rev=64229&r1=64228&r2=64229&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_param.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_param.cpp Tue Feb 10 13:49:53 2009
@@ -23,5 +23,67 @@
 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; 





More information about the cfe-commits mailing list