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