mirror of
https://github.com/intel/llvm.git
synced 2026-02-07 07:39:11 +08:00
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:
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 -------------------------===//
|
||||
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: clang -parse-noop -verify %s
|
||||
// RUN: clang -fsyntax-only -verify %s
|
||||
class C;
|
||||
class C {
|
||||
public:
|
||||
|
||||
52
clang/test/SemaTemplate/class-template-decl.cpp
Normal file
52
clang/test/SemaTemplate/class-template-decl.cpp
Normal 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
|
||||
Reference in New Issue
Block a user