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.

llvm-svn: 63973
This commit is contained in:
Douglas Gregor
2009-02-06 22:42:48 +00:00
parent dc93bbc4b0
commit cd72ba97e7
15 changed files with 447 additions and 80 deletions

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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")

View File

@@ -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 -------------------------===//

View File

@@ -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) {
}

View File

@@ -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);
}
//===----------------------------------------------------------------------===//

View File

@@ -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.

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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));
}

View File

@@ -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;
}

View File

@@ -1,4 +1,4 @@
// RUN: clang -parse-noop -verify %s
// RUN: clang -fsyntax-only -verify %s
class C;
class C {
public:

View File

@@ -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