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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64229 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 4eb866d..b297dd2 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -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(); 
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 25aea35..d17d244 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -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;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e3d132e..669fd92 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index c0c6e23..5eb2b21 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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,