diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-06 22:42:48 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-06 22:42:48 +0000 |
commit | ddc29e116db3c3f4144355e67a0137b38b6bb6d1 (patch) | |
tree | add7fd5470501bcc7a612dac9fbd03b5918b86da | |
parent | 4398a78095cd05a3be702fbab25bfe324a5d7946 (diff) |
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
-rw-r--r-- | Driver/PrintParserCallbacks.cpp | 3 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 26 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 16 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 14 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 9 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 7 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 30 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 18 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 269 | ||||
-rw-r--r-- | test/Parser/cxx-class.cpp | 2 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-decl.cpp | 52 |
15 files changed, 447 insertions, 80 deletions
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index 77d7ef18b8..b8957e520c 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -189,8 +189,7 @@ namespace { 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"; diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 64e4ea95b5..2183298f9d 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -27,15 +27,27 @@ class TemplateTemplateParmDecl; /// 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 @@ public: 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 @@ public: ~TemplateDecl(); /// Get the list of template parameters - TemplateParameterList *GetTemplateParameters() const { + TemplateParameterList *getTemplateParameters() const { return TemplateParams; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 91178d7b68..f9e0766010 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -469,6 +469,22 @@ DIAG(note_template_param_here, NOTE, "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") diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 271a3a8297..f735f3e792 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -335,8 +335,7 @@ public: 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 @@ public: 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 -------------------------===// diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 7fb427fe72..dc57d57410 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -80,7 +80,8 @@ public: TST_class, // C++ class type TST_typedef, TST_typeofType, - TST_typeofExpr + TST_typeofExpr, + TST_error // erroneous type }; // type-qualifiers @@ -260,7 +261,8 @@ public: 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 @@ private: 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) { } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 394939569e..d005ca3b06 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -22,19 +22,25 @@ using namespace clang; // 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); } //===----------------------------------------------------------------------===// diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 32b0011768..d5af384284 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -231,6 +231,13 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, 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. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index bbd5d4bb86..2ba1edc415 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1213,8 +1213,7 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { 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); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b2b0d8f59f..59c086f813 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -345,14 +345,17 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, 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 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, } 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 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // 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 diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e95c106f28..8836106e39 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -247,9 +247,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // 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 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } } + 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); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7d36291dd3..33b3781200 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -61,6 +61,7 @@ namespace clang { class ExtVectorType; class TypedefDecl; class TemplateDecl; + class TemplateParameterList; class ObjCInterfaceDecl; class ObjCCompatibleAliasDecl; class ObjCProtocolDecl; @@ -335,8 +336,7 @@ public: 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 @@ public: 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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 22b8ef2b1f..7ccc13c97d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -707,7 +707,8 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { 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 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { 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 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// 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 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; NamedDecl *PrevDecl = 0; - TemplateDecl *PrevTemplate = 0; bool Invalid = false; @@ -2892,11 +2879,6 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } 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 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, 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 @@ CreateNewDecl: // 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 @@ CreateNewDecl: // 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)); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index e15343a042..6c5f90afa5 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 @@ Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename, 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 @@ Sema::ActOnTemplateParameterList(unsigned Depth, 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; +} diff --gi |