Semantic checking for class template declarations and
redeclarations. For example, checks that a class template
redeclaration has the same template parameters as previous
declarations.

Detangled class-template checking from ActOnTag, whose logic was
getting rather convoluted because it tried to handle C, C++, and C++
template semantics in one shot.

Made some inroads toward eliminating extraneous "declaration does not
declare anything" errors by adding an "error" type specifier.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63973 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index e15343a..6c5f90a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -12,6 +12,7 @@
 //+//===----------------------------------------------------------------------===/
 
 #include "Sema.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/Parse/DeclSpec.h"
@@ -115,8 +116,12 @@
 							   PrevDecl);
   }
 
+  SourceLocation Loc = ParamNameLoc;
+  if (!ParamName)
+    Loc = KeyLoc;
+
   TemplateTypeParmDecl *Param
-    = TemplateTypeParmDecl::Create(Context, CurContext, ParamNameLoc, 
+    = TemplateTypeParmDecl::Create(Context, CurContext, Loc, 
                                    Depth, Position, ParamName, Typename);
   if (Invalid)
     Param->setInvalidDecl();
@@ -217,6 +222,266 @@
   if (ExportLoc.isValid())
     Diag(ExportLoc, diag::note_template_export_unsupported);
 
-  return TemplateParameterList::Create(Context, (Decl**)Params, NumParams);
+  return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
+                                       (Decl**)Params, NumParams, RAngleLoc);
 }
 
+Sema::DeclTy *
+Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+                         SourceLocation KWLoc, const CXXScopeSpec &SS,
+                         IdentifierInfo *Name, SourceLocation NameLoc,
+                         AttributeList *Attr,
+                         MultiTemplateParamsArg TemplateParameterLists) {
+  assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
+  assert(TK != TK_Reference && "Can only declare or define class templates");
+
+  // Check that we can declare a template here.
+  if (CheckTemplateDeclScope(S, TemplateParameterLists))
+    return 0;
+
+  TagDecl::TagKind Kind;
+  switch (TagSpec) {
+  default: assert(0 && "Unknown tag type!");
+  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
+  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
+  }
+
+  // There is no such thing as an unnamed class template.
+  if (!Name) {
+    Diag(KWLoc, diag::err_template_unnamed_class);
+    return 0;
+  }
+
+  // Find any previous declaration with this name.
+  LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
+                                           true);
+  assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
+  NamedDecl *PrevDecl = 0;
+  if (Previous.begin() != Previous.end())
+    PrevDecl = *Previous.begin();
+
+  DeclContext *SemanticContext = CurContext;
+  if (SS.isNotEmpty() && !SS.isInvalid()) {
+    SemanticContext = static_cast<DeclContext*>(SS.getScopeRep());
+
+    // FIXME: need to match up several levels of template parameter
+    // lists here.
+  }
+
+  // FIXME: member templates!
+  TemplateParameterList *TemplateParams 
+    = static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
+
+  // If there is a previous declaration with the same name, check
+  // whether this is a valid redeclaration.
+  ClassTemplateDecl *PrevClassTemplate 
+    = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+  if (PrevClassTemplate) {
+    // Ensure that the template parameter lists are compatible.
+    if (!TemplateParameterListsAreEqual(TemplateParams,
+                                   PrevClassTemplate->getTemplateParameters(),
+                                        /*Complain=*/true))
+      return 0;
+
+    // C++ [temp.class]p4:
+    //   In a redeclaration, partial specialization, explicit
+    //   specialization or explicit instantiation of a class template,
+    //   the class-key shall agree in kind with the original class
+    //   template declaration (7.1.5.3).
+    RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
+    if (PrevRecordDecl->getTagKind() != Kind) {
+      Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
+      Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
+      return 0;
+    }
+
+
+    // Check for redefinition of this class template.
+    if (TK == TK_Definition) {
+      if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
+        Diag(NameLoc, diag::err_redefinition) << Name;
+        Diag(Def->getLocation(), diag::note_previous_definition);
+        // FIXME: Would it make sense to try to "forget" the previous
+        // definition, as part of error recovery?
+        return 0;
+      }
+    }
+  } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
+    // Maybe we will complain about the shadowed template parameter.
+    DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
+    // Just pretend that we didn't see the previous declaration.
+    PrevDecl = 0;
+  } else if (PrevDecl) {
+    // C++ [temp]p5:
+    //   A class template shall not have the same name as any other
+    //   template, class, function, object, enumeration, enumerator,
+    //   namespace, or type in the same scope (3.3), except as specified
+    //   in (14.5.4).
+    Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+    Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+    return 0;
+  }
+
+  // If we had a scope specifier, we better have a previous template
+  // declaration!
+
+  TagDecl *NewClass = 
+    CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name,
+                          PrevClassTemplate? 
+                            PrevClassTemplate->getTemplatedDecl() : 0);
+
+  ClassTemplateDecl *NewTemplate
+    = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
+                                DeclarationName(Name), TemplateParams,
+                                NewClass);
+  
+  // Set the lexical context of these templates
+  NewClass->setLexicalDeclContext(CurContext);
+  NewTemplate->setLexicalDeclContext(CurContext);
+
+  if (TK == TK_Definition)
+    NewClass->startDefinition();
+
+  if (Attr)
+    ProcessDeclAttributeList(NewClass, Attr);
+
+  PushOnScopeChains(NewTemplate, S);
+
+  return NewTemplate;
+}
+
+/// \brief Determine whether the given template parameter lists are
+/// equivalent.
+///
+/// \param New  The new template parameter list, typically written in the 
+/// source code as part of a new template declaration.
+///
+/// \param Old  The old template parameter list, typically found via
+/// name lookup of the template declared with this template parameter
+/// list.
+///
+/// \param Complain  If true, this routine will produce a diagnostic if
+/// the template parameter lists are not equivalent.
+///
+/// \returns True if the template parameter lists are equal, false
+/// otherwise.
+bool 
+Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
+                                     TemplateParameterList *Old,
+                                     bool Complain,
+                                     bool IsTemplateTemplateParm) {
+  if (Old->size() != New->size()) {
+    if (Complain) {
+      Diag(New->getTemplateLoc(), diag::err_template_param_list_different_arity)
+        << (New->size() > Old->size())
+        << IsTemplateTemplateParm
+        << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
+      Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+        << IsTemplateTemplateParm
+        << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
+    }
+
+    return false;
+  }
+
+  for (TemplateParameterList::iterator OldParm = Old->begin(),
+         OldParmEnd = Old->end(), NewParm = New->begin();
+       OldParm != OldParmEnd; ++OldParm, ++NewParm) {
+    if ((*OldParm)->getKind() != (*NewParm)->getKind()) {
+      Diag((*NewParm)->getLocation(), diag::err_template_param_different_kind)
+        << IsTemplateTemplateParm;
+      Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
+        << IsTemplateTemplateParm;
+      return false;
+    }
+
+    if (isa<TemplateTypeParmDecl>(*OldParm)) {
+      // Okay; all template type parameters are equivalent (since we
+      // know we're at the same depth/level).
+#ifndef NDEBUG
+      QualType OldParmType 
+        = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
+      QualType NewParmType 
+        = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
+      assert(Context.getCanonicalType(OldParmType) == 
+             Context.getCanonicalType(NewParmType) && 
+             "type parameter mismatch?");
+#endif
+    } else if (NonTypeTemplateParmDecl *OldNTTP 
+                 = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
+      // The types of non-type template parameters must agree.
+      NonTypeTemplateParmDecl *NewNTTP
+        = cast<NonTypeTemplateParmDecl>(*NewParm);
+      if (Context.getCanonicalType(OldNTTP->getType()) !=
+            Context.getCanonicalType(NewNTTP->getType())) {
+        if (Complain) {
+          Diag(NewNTTP->getLocation(), 
+               diag::err_template_nontype_parm_different_type)
+            << NewNTTP->getType()
+            << IsTemplateTemplateParm;
+          Diag(OldNTTP->getLocation(), 
+               diag::note_template_nontype_parm_prev_declaration)
+            << OldNTTP->getType();
+        }
+        return false;
+      }
+    } else {
+      // The template parameter lists of template template
+      // parameters must agree.
+      // FIXME: Could we perform a faster "type" comparison here?
+      assert(isa<TemplateTemplateParmDecl>(*OldParm) && 
+             "Only template template parameters handled here");
+      TemplateTemplateParmDecl *OldTTP 
+        = cast<TemplateTemplateParmDecl>(*OldParm);
+      TemplateTemplateParmDecl *NewTTP
+        = cast<TemplateTemplateParmDecl>(*NewParm);
+      if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+                                          OldTTP->getTemplateParameters(),
+                                          Complain,
+                                          /*IsTemplateTemplateParm=*/true))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+/// \brief Check whether a template can be declared within this scope.
+///
+/// If the template declaration is valid in this scope, returns
+/// false. Otherwise, issues a diagnostic and returns true.
+bool 
+Sema::CheckTemplateDeclScope(Scope *S, 
+                             MultiTemplateParamsArg &TemplateParameterLists) {
+  assert(TemplateParameterLists.size() > 0 && "Not a template");
+
+  // Find the nearest enclosing declaration scope.
+  while ((S->getFlags() & Scope::DeclScope) == 0 ||
+         (S->getFlags() & Scope::TemplateParamScope) != 0)
+    S = S->getParent();
+  
+  TemplateParameterList *TemplateParams = 
+    static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+  SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
+  SourceRange TemplateRange 
+    = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
+
+  // C++ [temp]p2:
+  //   A template-declaration can appear only as a namespace scope or
+  //   class scope declaration.
+  DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+  while (Ctx && isa<LinkageSpecDecl>(Ctx)) {
+    if (cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
+      return Diag(TemplateLoc, diag::err_template_linkage)
+        << TemplateRange;
+
+    Ctx = Ctx->getParent();
+  }
+
+  if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
+    return false;
+
+  return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
+    << TemplateRange;
+}