From 4d9a16f36d3b768672d50e6d02000f982ae448d7 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 12 May 2009 23:25:50 +0000 Subject: [PATCH] Implement parsing for explicit instantiations of class templates, e.g., template class X; This also cleans up the propagation of template information through declaration parsing, which is used to improve some diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71608 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 9 ++- include/clang/Parse/Action.h | 56 ++++++++++++++++ include/clang/Parse/Parser.h | 57 +++++++++++++--- lib/Parse/ParseDecl.cpp | 28 +++----- lib/Parse/ParseDeclCXX.cpp | 74 ++++++++++++++++++--- lib/Parse/ParseTemplate.cpp | 44 ++++++++---- lib/Parse/Parser.cpp | 2 +- lib/Sema/SemaDecl.cpp | 7 +- test/SemaTemplate/temp_explicit.cpp | 19 ++++++ www/cxx_status.html | 6 +- 10 files changed, 248 insertions(+), 54 deletions(-) create mode 100644 test/SemaTemplate/temp_explicit.cpp diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index adfbb3540b..2912344e06 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -241,8 +241,13 @@ def warn_cxx0x_right_shift_in_template_arg : Warning< "use of right-shift operator ('>>') in template argument will require " "parentheses in C++0x">; def err_multiple_template_declarators : Error< - "%select{a template declaration|an explicit template instantiation}0 can " - "only %select{declare|instante}0 a single entity">; + "%select{|a template declaration|an explicit template specialization|" + "an explicit template instantiation}0 can " + "only %select{|declare|declare|instantiate}0 a single entity">; +def err_explicit_instantiation_with_definition : Error< + "explicit template instantiation cannot have a definition; if this " + "definition is meant to be an explicit specialization, add '<>' after the " + "'template' keyword">; def err_expected_qualified_after_typename : Error< "expected a qualified name after 'typename'">; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index f41e465fe0..10cdd73e1c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1319,6 +1319,62 @@ public: return DeclResult(); } + /// \brief Process the explicit instantiation of a class template + /// specialization. + /// + /// This routine is invoked when an explicit instantiation of a + /// class template specialization is encountered. In the following + /// example, ActOnExplicitInstantiation will be invoked to force the + /// instantiation of X: + /// + /// \code + /// template class X { /* ... */ }; + /// template class X; // explicit instantiation + /// \endcode + /// + /// \param S the current scope + /// + /// \param TemplateLoc the location of the 'template' keyword that + /// specifies that this is an explicit instantiation. + /// + /// \param TagSpec whether this declares a class, struct, or union + /// (template). + /// + /// \param KWLoc the location of the 'class', 'struct', or 'union' + /// keyword. + /// + /// \param SS the scope specifier preceding the template-id. + /// + /// \param Template the declaration of the class template that we + /// are instantiation. + /// + /// \param LAngleLoc the location of the '<' token in the template-id. + /// + /// \param TemplateArgs the template arguments used to form the + /// template-id. + /// + /// \param TemplateArgLocs the locations of the template arguments. + /// + /// \param RAngleLoc the location of the '>' token in the template-id. + /// + /// \param Attr attributes that apply to this instantiation. + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr) { + return DeclResult(); + } + + + /// \brief Called when the parser has parsed a C++ typename /// specifier that ends in an identifier, e.g., "typename T::type". /// diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index a11cd7d78d..ed20befc34 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -547,6 +547,43 @@ private: tok::TokenKind EarlyAbortIf = tok::unknown, bool ConsumeFinalToken = true); + /// \brief Contains information about any template-specific + /// information that has been parsed prior to parsing declaration + /// specifiers. + struct ParsedTemplateInfo { + ParsedTemplateInfo() + : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } + + ParsedTemplateInfo(TemplateParameterLists *TemplateParams, + bool isSpecialization) + : Kind(isSpecialization? ExplicitSpecialization : Template), + TemplateParams(TemplateParams) { } + + explicit ParsedTemplateInfo(SourceLocation TemplateLoc) + : Kind(ExplicitInstantiation), + TemplateLoc(TemplateLoc) { } + + /// \brief The kind of template we are parsing. + enum { + /// \brief We are not parsing a template at all. + NonTemplate = 0, + /// \brief We are parsing a template declaration. + Template, + /// \brief We are parsing an explicit specialization. + ExplicitSpecialization, + /// \brief We are parsing an explicit instantiation. + ExplicitInstantiation + } Kind; + + /// \brief The template parameter lists, for template declarations + /// and explicit specializations. + TemplateParameterLists *TemplateParams; + + /// \brief The location of the 'template' keyword, for an explicit + /// instantiation. + SourceLocation TemplateLoc; + }; + //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. DeclGroupPtrTy ParseExternalDeclaration(); @@ -823,14 +860,15 @@ private: DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl); bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, - TemplateParameterLists *TemplateParams, + const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS); void ParseDeclarationSpecifiers(DeclSpec &DS, - TemplateParameterLists *TemplateParams = 0, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none); bool ParseOptionalTypeSpecifier(DeclSpec &DS, int &isInvalid, const char *&PrevSpec, - TemplateParameterLists *TemplateParams = 0); + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + void ParseSpecifierQualifierList(DeclSpec &DS); void ParseObjCTypeQualifierList(ObjCDeclSpec &DS); @@ -1025,7 +1063,7 @@ private: const CXXScopeSpec *SS = 0); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, - TemplateParameterLists *TemplateParams = 0, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); @@ -1051,13 +1089,15 @@ private: typedef llvm::SmallVector TemplateParameterList; // C++ 14.1: Template Parameters [temp.param] + DeclPtrTy ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none); DeclPtrTy ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, - AccessSpecifier AS=AS_none); + AccessSpecifier AS); DeclPtrTy ParseSingleDeclarationAfterTemplate( unsigned Context, - TemplateParameterLists *TemplateParams, - SourceLocation TemplateLoc, + const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, AccessSpecifier AS=AS_none); bool ParseTemplateParameters(unsigned Depth, @@ -1094,7 +1134,8 @@ private: TemplateArgIsTypeList &TemplateArgIsType, TemplateArgLocationList &TemplateArgLocations); void *ParseTemplateArgument(bool &ArgIsType); - DeclPtrTy ParseExplicitInstantiation(SourceLocation &DeclEnd); + DeclPtrTy ParseExplicitInstantiation(SourceLocation TemplateLoc, + SourceLocation &DeclEnd); //===--------------------------------------------------------------------===// // GNU G++: Type Traits [Type-Traits.html in the GCC manual] diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9d7d9d400f..cdf84bfad6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -234,14 +234,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::kw_template: - if (NextToken().isNot(tok::less)) { - SingleDecl = ParseExplicitInstantiation(DeclEnd); - break; - } - // Fall through for template declarations and specializations - case tok::kw_export: - SingleDecl = ParseTemplateDeclarationOrSpecialization(Context, DeclEnd); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; case tok::kw_namespace: SingleDecl = ParseNamespace(Context, DeclEnd); @@ -521,7 +515,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) { /// other pieces of declspec after it, it returns true. /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, - TemplateParameterLists *TemplateParams, + const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS) { assert(Tok.is(tok::identifier) && "should have identifier"); @@ -576,7 +570,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, if (TagKind == tok::kw_enum) ParseEnumSpecifier(Loc, DS, AS); else - ParseClassSpecifier(TagKind, Loc, DS, TemplateParams, AS); + ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS); return true; } } @@ -622,7 +616,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, - TemplateParameterLists *TemplateParams, + const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS) { DS.SetRangeStart(Tok.getLocation()); while (1) { @@ -686,7 +680,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typename. if (TypeRep == 0) { ConsumeToken(); // Eat the scope spec so the identifier is current. - if (ParseImplicitInt(DS, &SS, TemplateParams, AS)) continue; + if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue; goto DoneWithDeclSpec; } @@ -748,7 +742,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (TypeRep == 0) { - if (ParseImplicitInt(DS, 0, TemplateParams, AS)) continue; + if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue; goto DoneWithDeclSpec; } @@ -934,7 +928,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateParams, AS); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS); continue; } @@ -1047,7 +1041,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, const char *&PrevSpec, - TemplateParameterLists *TemplateParams){ + const ParsedTemplateInfo &TemplateInfo) { SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { @@ -1056,7 +1050,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec,TemplateParams); + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo); // Otherwise, not a type specifier. return false; case tok::coloncolon: // ::foo::bar @@ -1067,7 +1061,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec,TemplateParams); + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo); // Otherwise, not a type specifier. return false; @@ -1156,7 +1150,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateParams); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo); return true; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 0718d3bfb5..56503961fa 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -392,7 +392,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// 'union' void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, - TemplateParameterLists *TemplateParams, + const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS) { DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) @@ -475,15 +475,72 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Create the tag portion of the class or class template. Action::DeclResult TagOrTempResult; + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + + // FIXME: When TK == TK_Reference and we have a template-id, we need + // to turn that template-id into a type. + if (TemplateId && TK != Action::TK_Reference) { - // Explicit specialization or class template partial - // specialization. Let semantic analysis decide. + // Explicit specialization, class template partial specialization, + // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); - TagOrTempResult - = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK, + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TK == Action::TK_Declaration) { + // This is an explicit instantiation of a class template. + TagOrTempResult + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.TemplateLoc, + TagType, + StartLoc, + SS, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc, + Attr); + } else { + // This is an explicit specialization or a class template + // partial specialization. + TemplateParameterLists FakedParamLists; + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // This looks like an explicit instantiation, because we have + // something like + // + // template class Foo + // + // but it is actually a declaration. Most likely, this was + // meant to be an explicit specialization, but the user forgot + // the '<>' after 'template'. + assert(TK == Action::TK_Definition && "Can only get a definition here"); + + SourceLocation LAngleLoc + = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(TemplateId->TemplateNameLoc, + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << CodeModificationHint::CreateInsertion(LAngleLoc, "<>"); + + // Create a fake template parameter list that contains only + // "template<>", so that we treat this construct as a class + // template specialization. + FakedParamLists.push_back( + Actions.ActOnTemplateParameterList(0, SourceLocation(), + TemplateInfo.TemplateLoc, + LAngleLoc, + 0, 0, + LAngleLoc)); + TemplateParams = &FakedParamLists; + } + + // Build the class template specialization. + TagOrTempResult + = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK, StartLoc, SS, TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, @@ -495,6 +552,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); + } TemplateId->Destroy(); } else if (TemplateParams && TK != Action::TK_Reference) TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, @@ -691,8 +749,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { if (Tok.is(tok::kw_template)) { SourceLocation DeclEnd; - ParseTemplateDeclarationOrSpecialization(Declarator::MemberContext, DeclEnd, - AS); + ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, + AS); return; } @@ -708,7 +766,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // decl-specifier-seq: // Parse the common declaration-specifiers piece. DeclSpec DS; - ParseDeclarationSpecifiers(DS, 0, AS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); if (Tok.is(tok::semi)) { ConsumeToken(); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 22d11779ab..490f2769e1 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -18,6 +18,18 @@ #include "AstGuard.h" using namespace clang; +/// \brief Parse a template declaration, explicit instantiation, or +/// explicit specialization. +Parser::DeclPtrTy +Parser::ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS) { + if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) + return ParseExplicitInstantiation(ConsumeToken(), DeclEnd); + + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); +} + /// \brief Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists @@ -64,6 +76,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // defining A::B receives just the inner template parameter list // (and retrieves the outer template parameter list from its // context). + bool isSpecialiation = true; TemplateParameterLists ParamLists; do { // Consume the 'export', if any. @@ -87,6 +100,9 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, RAngleLoc); + if (!TemplateParams.empty()) + isSpecialiation = false; + ParamLists.push_back( Actions.ActOnTemplateParameterList(ParamLists.size(), ExportLoc, TemplateLoc, LAngleLoc, @@ -95,8 +111,9 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); // Parse the actual template declaration. - return ParseSingleDeclarationAfterTemplate(Context, &ParamLists, - SourceLocation(), + return ParseSingleDeclarationAfterTemplate(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialiation), DeclEnd, AS); } @@ -123,14 +140,16 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, Parser::DeclPtrTy Parser::ParseSingleDeclarationAfterTemplate( unsigned Context, - TemplateParameterLists *TemplateParams, - SourceLocation TemplateLoc, + const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, AccessSpecifier AS) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + "Template information required"); + // Parse the declaration specifiers. DeclSpec DS; // FIXME: Pass TemplateLoc through for explicit template instantiations - ParseDeclarationSpecifiers(DS, TemplateParams, AS); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); @@ -156,7 +175,7 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::comma)) { Diag(Tok, diag::err_multiple_template_declarators) - << (TemplateParams == 0); + << (int)TemplateInfo.Kind; SkipUntil(tok::semi, true, false); return ThisDecl; } @@ -785,11 +804,10 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, /// /// explicit-instantiation: /// 'template' declaration -Parser::DeclPtrTy Parser::ParseExplicitInstantiation(SourceLocation &DeclEnd) { - assert(Tok.is(tok::kw_template) && NextToken().isNot(tok::less) && - "Token does not start an explicit instantiation."); - - SourceLocation TemplateLoc = ConsumeToken(); - return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, 0, - TemplateLoc, DeclEnd, AS_none); +Parser::DeclPtrTy +Parser::ParseExplicitInstantiation(SourceLocation TemplateLoc, + SourceLocation &DeclEnd) { + return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, + ParsedTemplateInfo(TemplateLoc), + DeclEnd, AS_none); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d07d52e58c..12e584377d 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -480,7 +480,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // Parse the common declaration-specifiers piece. DeclSpec DS; - ParseDeclarationSpecifiers(DS, 0, AS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b233021c42..523e71e9b7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1017,13 +1017,16 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { // FIXME: Warn on useless const/volatile // FIXME: Warn on useless static/extern/typedef/private_extern/mutable // FIXME: Warn on useless attributes - TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_union || - DS.getTypeSpecType() == DeclSpec::TST_enum) + DS.getTypeSpecType() == DeclSpec::TST_enum) { + if (!DS.getTypeRep()) // We probably had an error + return DeclPtrTy(); + Tag = dyn_cast(static_cast(DS.getTypeRep())); + } if (RecordDecl *Record = dyn_cast_or_null(Tag)) { if (!Record->getDeclName() && Record->isDefinition() && diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp new file mode 100644 index 0000000000..884fc38167 --- /dev/null +++ b/test/SemaTemplate/temp_explicit.cpp @@ -0,0 +1,19 @@ +// RUN: clang-cc -fsyntax-only -verify %s +// +// Tests explicit instantiation of templates. +template class X0 { }; + +namespace N { + template class X1 { }; +} + +template class X0; +template class X0; + +template class N::X1; +template class ::N::X1; + +using namespace N; +template class X1; + +template class X0 { }; // expected-error{{explicit specialization}} diff --git a/www/cxx_status.html b/www/cxx_status.html index 40490e57ea..9be7ffc274 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -2053,11 +2053,11 @@ welcome!

    14.7.2 [temp.explicit] + + - - - + Function templates cannot be instantiated     14.7.3 [temp.expl.spec] -- 2.40.0