diff options
-rw-r--r-- | include/clang/AST/Decl.h | 5 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 10 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 25 | ||||
-rw-r--r-- | test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp | 18 |
8 files changed, 95 insertions, 15 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 0fb7fc478d..1d6c9c1872 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1340,6 +1340,11 @@ public: } } + /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into a tag kind. It is an error to provide a type specifier + /// which *isn't* a tag kind here. + static TagKind getTagKindForTypeSpec(unsigned TypeSpec); + TagKind getTagKind() const { return TagKind(TagDeclKind); } diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 31acc87cb4..370fed9966 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1591,15 +1591,17 @@ public: /// \param Template A template whose specialization results in a /// type, e.g., a class template or template template parameter. /// - /// \param IsSpecialization true when we are naming the class - /// template specialization as part of an explicit class - /// specialization or class template partial specialization. + /// \param TagSpec The tag spec that was provided as part of the + /// elaborated-type-specifier, or TST_unspecified if this was not + /// an elaborated type. virtual TypeResult ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { + SourceLocation RAngleLoc, + DeclSpec::TST TagSpec = DeclSpec::TST_unspecified, + SourceLocation TagLoc = SourceLocation()) { return TypeResult(); }; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index fc19e61a09..41ba1f1df9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -22,6 +22,8 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" #include <vector> using namespace clang; @@ -708,6 +710,16 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { return 0; } +TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { + switch (TypeSpec) { + default: llvm::llvm_unreachable("unexpected type specifier"); + case DeclSpec::TST_struct: return TK_struct; + case DeclSpec::TST_class: return TK_class; + case DeclSpec::TST_union: return TK_union; + case DeclSpec::TST_enum: return TK_enum; + } +} + //===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f50147c599..59359530e3 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -606,7 +606,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // to turn that template-id into a type. bool Owned = false; - if (TemplateId && TUK != Action::TUK_Reference && TUK != Action::TUK_Friend) { + if (TemplateId) { // Explicit specialization, class template partial specialization, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(Actions, @@ -629,6 +629,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc, Attr); + } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) { + Action::TypeResult TypeResult = + Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc, + TagType, StartLoc); + + TemplateId->Destroy(); + + if (TypeResult.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, + DiagID, TypeResult.get())) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } else { // This is an explicit specialization or a class template // partial specialization. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 746c28af62..f1e4968fd2 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2396,7 +2396,9 @@ public: SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc); + SourceLocation RAngleLoc, + DeclSpec::TST TagSpec, + SourceLocation TagLoc); OwningExprResult BuildTemplateIdExpr(TemplateName Template, SourceLocation TemplateNameLoc, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index abf95283cd..e929b5f0d6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3966,14 +3966,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, "Nameless record must be a definition!"); OwnedDecl = false; - 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; - case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break; - } + TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); if (TUK != TUK_Reference) { if (TemplateParameterList *TemplateParams diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 119e17f814..8eaa9fb397 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1121,7 +1121,9 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { + SourceLocation RAngleLoc, + DeclSpec::TST TagSpec, + SourceLocation TagLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. @@ -1137,6 +1139,25 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, if (Result.isNull()) return true; + // If we were given a tag specifier, verify it. + if (TagSpec != DeclSpec::TST_unspecified) { + TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + + if (const RecordType *T = Result->getAs<RecordType>()) { + RecordDecl *D = T->getDecl(); + + IdentifierInfo *Id = D->getIdentifier(); + assert(Id && "templated class must have an identifier"); + + if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { + Diag(TagLoc, diag::err_use_with_wrong_tag) + << Id + << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), + D->getKindName()); + } + } + } + return Result.getAsOpaquePtr(); } @@ -2497,6 +2518,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, SourceLocation RAngleLoc, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists) { + assert(TUK == TUK_Declaration || TUK == TUK_Definition); + // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); ClassTemplateDecl *ClassTemplate diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp new file mode 100644 index 0000000000..4dc1cc7d7a --- /dev/null +++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// elaborated-type-specifier: +// class-key '::'? nested-name-specifier? 'template'? simple-template-id +// Tests that this form is accepted by the compiler but does not follow +// the elaborated lookup rules of [basic.lookup.elab]. + +template <typename> class Ident {}; + +namespace A { + template <typename> void Ident(); + + class Ident<int> AIdent; // expected-error {{refers to a function template}} + class ::Ident<int> AnotherIdent; +} + +class Ident<int> GlobalIdent; +union Ident<int> GlobalIdent; // expected-error {{ tag type that does not match }} |