[cfe-commits] r63973 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h lib/AST/DeclTemplate.cpp lib/Parse/DeclSpec.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/Parser/cxx-class.cpp test/SemaTemplate/ test/SemaTemplate/class-template-decl.cpp

Douglas Gregor dgregor at apple.com
Fri Feb 6 14:42:48 PST 2009


Author: dgregor
Date: Fri Feb  6 16:42:48 2009
New Revision: 63973

URL: http://llvm.org/viewvc/llvm-project?rev=63973&view=rev
Log:
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.


Added:
    cfe/trunk/test/SemaTemplate/
    cfe/trunk/test/SemaTemplate/class-template-decl.cpp
Modified:
    cfe/trunk/Driver/PrintParserCallbacks.cpp
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/Parse/DeclSpec.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/Parser/cxx-class.cpp

Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=63973&r1=63972&r2=63973&view=diff

==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Fri Feb  6 16:42:48 2009
@@ -189,8 +189,7 @@
     virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
                              SourceLocation KWLoc, const CXXScopeSpec &SS,
                              IdentifierInfo *Name, SourceLocation NameLoc,
-                             AttributeList *Attr,
-                             MultiTemplateParamsArg TemplateParameterLists) {
+                             AttributeList *Attr) {
       // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
       // is (struct/union/enum/class).
       llvm::cout << __FUNCTION__ << "\n";

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Fri Feb  6 16:42:48 2009
@@ -27,15 +27,27 @@
 /// TemplateParameterList - Stores a list of template parameters for a
 /// TemplateDecl and its derived classes.
 class TemplateParameterList {
-  /// NumParams - The number of template parameters in this template
+  /// The location of the 'template' keyword.
+  SourceLocation TemplateLoc;
+
+  /// The locations of the '<' and '>' angle brackets.
+  SourceLocation LAngleLoc, RAngleLoc;
+
+  /// The number of template parameters in this template
   /// parameter list.
   unsigned NumParams;
 
-  TemplateParameterList(Decl **Params, unsigned NumParams);
+  TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
+                        Decl **Params, unsigned NumParams,
+                        SourceLocation RAngleLoc);
 
 public:
-  static TemplateParameterList *Create(ASTContext &C, Decl **Params,
-                                       unsigned NumParams);
+  static TemplateParameterList *Create(ASTContext &C, 
+                                       SourceLocation TemplateLoc,
+                                       SourceLocation LAngleLoc,
+                                       Decl **Params,
+                                       unsigned NumParams,
+                                       SourceLocation RAngleLoc);
 
   /// iterator - Iterates through the template parameters in this list.
   typedef Decl** iterator;
@@ -51,6 +63,10 @@
   const_iterator end() const { return begin() + NumParams; }
 
   unsigned size() const { return NumParams; }
+
+  SourceLocation getTemplateLoc() const { return TemplateLoc; }
+  SourceLocation getLAngleLoc() const { return LAngleLoc; }
+  SourceLocation getRAngleLoc() const { return RAngleLoc; }
 };
 
 //===----------------------------------------------------------------------===//
@@ -86,7 +102,7 @@
   ~TemplateDecl();
 
   /// Get the list of template parameters
-  TemplateParameterList *GetTemplateParameters() const {
+  TemplateParameterList *getTemplateParameters() const {
     return TemplateParams;
   }
 

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Fri Feb  6 16:42:48 2009
@@ -469,6 +469,22 @@
      "template parameter is declared here")
 DIAG(note_template_export_unsupported, NOTE, 
      "exported templates are unsupported")
+DIAG(err_template_outside_namespace_or_class_scope, ERROR,
+     "templates can only be declared in namespace or class scope")
+DIAG(err_template_linkage, ERROR,
+     "templates must have C++ linkage")
+DIAG(err_template_unnamed_class, ERROR,
+     "cannot declare a class template with no name")
+DIAG(err_template_param_list_different_arity, ERROR,
+     "%select{too few|too many}0 template parameters in template %select{|template parameter }1redeclaration")
+DIAG(note_template_prev_declaration, NOTE,
+     "previous template %select{declaration|template parameter}0 is here")
+DIAG(err_template_param_different_kind, ERROR,
+     "template parameter has a different kind in template %select{|template parameter }0redeclaration")
+DIAG(err_template_nontype_parm_different_type, ERROR,
+     "template non-type parameter has a different type %0 in template %select{|template parameter }1redeclaration")
+DIAG(note_template_nontype_parm_prev_declaration, NOTE,
+     "previous non-type template parameter with type %0 is here")
 
 DIAG(err_unexpected_typedef, ERROR,
      "unexpected type name %0: expected expression")

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Feb  6 16:42:48 2009
@@ -335,8 +335,7 @@
   virtual DeclTy *ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                            SourceLocation KWLoc, const CXXScopeSpec &SS,
                            IdentifierInfo *Name, SourceLocation NameLoc,
-                           AttributeList *Attr,
-                           MultiTemplateParamsArg TemplateParameterLists) {
+                           AttributeList *Attr) {
     // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
     // is (struct/union/enum/class).
     return 0;
@@ -1112,6 +1111,17 @@
     return 0;
   }
 
+  // \brief Process the declaration or definition of a class template
+  // with the given template parameter lists.
+  virtual DeclTy *
+  ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+                     SourceLocation KWLoc, const CXXScopeSpec &SS,
+                     IdentifierInfo *Name, SourceLocation NameLoc,
+                     AttributeList *Attr,
+                     MultiTemplateParamsArg TemplateParameterLists) {
+    return 0;
+  }
+
   
   //===----------------------- Obj-C Declarations -------------------------===//
   

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

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Fri Feb  6 16:42:48 2009
@@ -80,7 +80,8 @@
     TST_class,        // C++ class type
     TST_typedef,
     TST_typeofType,
-    TST_typeofExpr
+    TST_typeofExpr,
+    TST_error         // erroneous type
   };
   
   // type-qualifiers
@@ -260,7 +261,8 @@
   bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec);
   bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
                        Action::TypeTy *TypeRep = 0);
-  
+  bool SetTypeSpecError();
+
   bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
                    const LangOptions &Lang);
   
@@ -761,7 +763,8 @@
   
 public:
   Declarator(const DeclSpec &ds, TheContext C)
-    : DS(ds), Identifier(0), Context(C), Kind(DK_Abstract), InvalidType(false),
+    : DS(ds), Identifier(0), Context(C), Kind(DK_Abstract), 
+      InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
       GroupingParens(false), AttrList(0), AsmLabel(0), Type(0),
       InlineParamsUsed(false) {
   }

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

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Fri Feb  6 16:42:48 2009
@@ -22,19 +22,25 @@
 // TemplateParameterList Implementation
 //===----------------------------------------------------------------------===//
 
-TemplateParameterList::TemplateParameterList(Decl **Params, unsigned NumParams)
-  : NumParams(NumParams) {
+TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+                                             SourceLocation LAngleLoc,
+                                             Decl **Params, unsigned NumParams,
+                                             SourceLocation RAngleLoc)
+  : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+    NumParams(NumParams) {
   for (unsigned Idx = 0; Idx < NumParams; ++Idx)
     begin()[Idx] = Params[Idx];
 }
 
 TemplateParameterList *
-TemplateParameterList::Create(ASTContext &C, Decl **Params,
-                              unsigned NumParams) {
+TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
+                              SourceLocation LAngleLoc, Decl **Params,
+                              unsigned NumParams, SourceLocation RAngleLoc) {
   unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams;
   unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment;
   void *Mem = C.Allocate(Size, Align);
-  return new (Mem) TemplateParameterList(Params, NumParams);
+  return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, 
+                                         NumParams, RAngleLoc);
 }
 
 //===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/Parse/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Parse/DeclSpec.cpp Fri Feb  6 16:42:48 2009
@@ -231,6 +231,13 @@
   return false;
 }
 
+bool DeclSpec::SetTypeSpecError() {
+  TypeSpecType = TST_error;
+  TypeRep = 0;
+  TSTLoc = SourceLocation();
+  return false;
+}
+
 bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
                            const LangOptions &Lang) {
   // Duplicates turn into warnings pre-C99.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Feb  6 16:42:48 2009
@@ -1213,8 +1213,7 @@
   else
     TK = Action::TK_Reference;
   DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc,
-                                     SS, Name, NameLoc, Attr, 
-                                     Action::MultiTemplateParamsArg(Actions));
+                                     SS, Name, NameLoc, Attr);
   
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri Feb  6 16:42:48 2009
@@ -345,14 +345,17 @@
     return;
   }
 
-  // Create the tag portion of the class, possibly resulting in a template.
-  DeclTy *TagOrTempDecl
-    = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, 
-                       NameLoc, Attr,
-                       Action::MultiTemplateParamsArg(
-                         Actions,
-                         TemplateParams? &(*TemplateParams)[0] : 0,
-                         TemplateParams? TemplateParams->size() : 0));
+  // Create the tag portion of the class or class template.
+  DeclTy *TagOrTempDecl;
+  if (TemplateParams && TK != Action::TK_Reference)
+    TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc,
+                                               SS, Name, NameLoc, Attr,
+                       Action::MultiTemplateParamsArg(Actions, 
+                                                      &(*TemplateParams)[0],
+                                                      TemplateParams->size()));
+  else
+    TagOrTempDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, 
+                                     NameLoc, Attr);
 
   // Parse the optional base clause (C++ only).
   if (getLang().CPlusPlus && Tok.is(tok::colon)) {
@@ -372,7 +375,9 @@
   }
 
   const char *PrevSpec = 0;
-  if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, TagOrTempDecl))
+  if (!TagOrTempDecl)
+    DS.SetTypeSpecError();
+  else if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, TagOrTempDecl))
     Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
 }
 
@@ -731,7 +736,12 @@
   // Enter a scope for the class.
   ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
 
-  Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+  if (TagDecl)
+    Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+  else {
+    SkipUntil(tok::r_brace, false, false);
+    return;
+  }
 
   // C++ 11p3: Members of a class defined with the keyword class are private
   // by default. Members of a class defined with the keywords struct or union

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Fri Feb  6 16:42:48 2009
@@ -247,9 +247,9 @@
   // Handle the template <...> part.
   SourceLocation TemplateLoc = ConsumeToken();
   TemplateParameterList TemplateParams; 
-  SourceLocation LParenLoc, RParenLoc;
-  if(!ParseTemplateParameters(Depth + 1, TemplateParams, LParenLoc,
-                              RParenLoc)) {
+  SourceLocation LAngleLoc, RAngleLoc;
+  if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
+                              RAngleLoc)) {
     return 0;
   }
 
@@ -288,8 +288,15 @@
     }
   }
 
+  TemplateParamsTy *ParamList = 
+    Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
+                                       TemplateLoc, LAngleLoc,
+                                       &TemplateParams[0], 
+                                       TemplateParams.size(),
+                                       RAngleLoc);
+
   return Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
-                                                &TemplateParams, ParamName,
+                                                ParamList, ParamName,
                                                 NameLoc, Depth, Position);
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Feb  6 16:42:48 2009
@@ -61,6 +61,7 @@
   class ExtVectorType;
   class TypedefDecl;
   class TemplateDecl;
+  class TemplateParameterList;
   class ObjCInterfaceDecl;
   class ObjCCompatibleAliasDecl;
   class ObjCProtocolDecl;
@@ -335,8 +336,7 @@
   virtual DeclTy *ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                            SourceLocation KWLoc, const CXXScopeSpec &SS,
                            IdentifierInfo *Name, SourceLocation NameLoc,
-                           AttributeList *Attr,
-                           MultiTemplateParamsArg TemplateParameterLists);
+                           AttributeList *Attr);
   
   virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart,
                          IdentifierInfo *ClassName,
@@ -1505,6 +1505,20 @@
                              DeclTy **Params, unsigned NumParams,
                              SourceLocation RAngleLoc);
   
+  virtual DeclTy *
+  ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+                     SourceLocation KWLoc, const CXXScopeSpec &SS,
+                     IdentifierInfo *Name, SourceLocation NameLoc,
+                     AttributeList *Attr,
+                     MultiTemplateParamsArg TemplateParameterLists);
+
+  bool TemplateParameterListsAreEqual(TemplateParameterList *New,
+                                      TemplateParameterList *Old,
+                                      bool Complain,
+                                      bool IsTemplateTemplateParm = false);
+  
+  bool CheckTemplateDeclScope(Scope *S, 
+                              MultiTemplateParamsArg &TemplateParameterLists);
 
   // Objective-C declarations.
   virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Feb  6 16:42:48 2009
@@ -707,7 +707,8 @@
       return Tag;
   }
 
-  if (!DS.isMissingDeclaratorOk()) {
+  if (!DS.isMissingDeclaratorOk() && 
+      DS.getTypeSpecType() != DeclSpec::TST_error) {
     // Warn about typedefs of enums without names, since this is an
     // extension in both Microsoft an GNU.
     if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
@@ -717,10 +718,6 @@
       return Tag;
     }
 
-    // FIXME: This diagnostic is emitted even when various previous
-    // errors occurred (see e.g. test/Sema/decl-invalid.c). However,
-    // DeclSpec has no means of communicating this information, and the
-    // responsible parser functions are quite far apart.
     Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
       << DS.getSourceRange();
     return 0;
@@ -2798,22 +2795,13 @@
 /// former case, Name will be non-null.  In the later case, Name will be null.
 /// TagSpec indicates what kind of tag this is. TK indicates whether this is a
 /// reference/declaration/definition of a tag.
-///
-/// This creates and returns template declarations if any template parameter
-/// lists are given.
 Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                              SourceLocation KWLoc, const CXXScopeSpec &SS,
                              IdentifierInfo *Name, SourceLocation NameLoc,
-                             AttributeList *Attr,
-                             MultiTemplateParamsArg TemplateParameterLists) {
+                             AttributeList *Attr) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TK == TK_Definition) &&
          "Nameless record must be a definition!");
-  assert((TemplateParameterLists.size() == 0 || TK != TK_Reference) &&
-         "Can't have a reference to a template");
-  assert((TemplateParameterLists.size() == 0 || 
-          TagSpec != DeclSpec::TST_enum) &&
-         "No such thing as an enum template");
 
   TagDecl::TagKind Kind;
   switch (TagSpec) {
@@ -2827,7 +2815,6 @@
   DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   NamedDecl *PrevDecl = 0;
-  TemplateDecl *PrevTemplate = 0;
 
   bool Invalid = false;
 
@@ -2892,11 +2879,6 @@
   }
 
   if (PrevDecl) {    
-    // If we found a template, keep track of the template and its
-    // underlying declaration.
-    if ((PrevTemplate = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl)))
-      PrevDecl = PrevTemplate->getTemplatedDecl();
-
     if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
       // If this is a use of a previous tag, or if the tag is already declared
       // in the same scope (so that the definition/declaration completes or
@@ -2911,7 +2893,6 @@
           Name = 0;
           PrevDecl = 0;
           Invalid = true;
-          // FIXME: Add template/non-template redecl check
         } else {
           // If this is a use, just return the declaration we found.
 
@@ -3025,7 +3006,6 @@
   // declaration of the same entity, the two will be linked via
   // PrevDecl.
   TagDecl *New;
-  ClassTemplateDecl *NewTemplate = 0;
 
   if (Kind == TagDecl::TK_enum) {
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
@@ -3039,28 +3019,11 @@
 
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // struct X { int A; } D;    D should chain to X.
-    if (getLangOptions().CPlusPlus) {
+    if (getLangOptions().CPlusPlus)
       // FIXME: Look for a way to use RecordDecl for simple structs.
       New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
                                   cast_or_null<CXXRecordDecl>(PrevDecl));
-
-      // If there's are template parameters, then this must be a class
-      // template. Create the template decl node also.
-      // FIXME: Do we always create template decls? We may not for forward
-      // declarations.
-      // FIXME: What are we actually going to do with the template decl?
-      if (TemplateParameterLists.size() > 0) {
-        // FIXME: The allocation of the parameters is probably incorrect.
-        // FIXME: Does the TemplateDecl have the same name as the class?
-        TemplateParameterList *Params =
-          TemplateParameterList::Create(Context,
-                                        (Decl **)TemplateParameterLists.get(),
-                                        TemplateParameterLists.size());
-        NewTemplate = ClassTemplateDecl::Create(Context, DC, Loc,
-                                                DeclarationName(Name), Params,
-                                                New);
-      }
-    } else
+    else
       New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
                                cast_or_null<RecordDecl>(PrevDecl));
   }

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Feb  6 16:42:48 2009
@@ -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;
+}

Modified: cfe/trunk/test/Parser/cxx-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-class.cpp?rev=63973&r1=63972&r2=63973&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-class.cpp (original)
+++ cfe/trunk/test/Parser/cxx-class.cpp Fri Feb  6 16:42:48 2009
@@ -1,4 +1,4 @@
-// RUN: clang -parse-noop -verify %s
+// RUN: clang -fsyntax-only -verify %s
 class C;
 class C {
 public:

Added: cfe/trunk/test/SemaTemplate/class-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-decl.cpp?rev=63973&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-decl.cpp (added)
+++ cfe/trunk/test/SemaTemplate/class-template-decl.cpp Fri Feb  6 16:42:48 2009
@@ -0,0 +1,52 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T> class A;
+
+extern "C++" {
+  template<typename T> class B;
+}
+
+namespace N {
+  template<typename T> class C;
+}
+
+extern "C" {
+  template<typename T> class D; // expected-error{{templates must have C++ linkage}}
+}
+
+template<class U> class A; // expected-note{{previous template declaration is here}}\
+                           // expected-note{{previous use is here}}
+
+template<int N> class A; // expected-error{{template parameter has a different kind in template redeclaration}}
+
+template<class T> struct A; // expected-error{{use of 'A' with tag type that does not match previous declaration}}
+
+template<int N> class NonTypeTemplateParm;
+
+typedef int INT;
+
+template<INT M> class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' is here}}
+
+template<long> class NonTypeTemplateParm; // expected-error{{template non-type parameter has a different type 'long' in template redeclaration}}
+
+template<template<typename T> class X> class TemplateTemplateParm;
+
+template<template<class> class Y> class TemplateTemplateParm; // expected-note{{previous template declaration is here}} \
+      // expected-note{{previous template template parameter is here}}
+
+template<typename> class TemplateTemplateParm; // expected-error{{template parameter has a different kind in template redeclaration}}
+
+template<template<typename T, int> class X> class TemplateTemplateParm; // expected-error{{too many template parameters in template template parameter redeclaration}}
+
+#if 0
+// FIXME: parse template declarations in these scopes, so that we can
+// complain about the one at function scope.
+class X {
+public:
+  template<typename T> class C;
+};
+
+void f() {
+  template<typename T> class X;
+}
+#endif





More information about the cfe-commits mailing list