forked from OSchip/llvm-project
Implement parsing for explicit instantiations of class templates, e.g.,
template class X<int>; This also cleans up the propagation of template information through declaration parsing, which is used to improve some diagnostics. llvm-svn: 71608
This commit is contained in:
parent
e83b560e06
commit
1b57ff32a8
|
@ -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'">;
|
||||
|
|
|
@ -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<int>:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T> class X { /* ... */ };
|
||||
/// template class X<int>; // 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".
|
||||
///
|
||||
|
|
|
@ -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<DeclPtrTy, 4> 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]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<X>
|
||||
//
|
||||
// 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();
|
||||
|
|
|
@ -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<T>::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);
|
||||
}
|
||||
|
|
|
@ -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] ';'
|
||||
|
|
|
@ -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<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
|
||||
}
|
||||
|
||||
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
|
||||
if (!Record->getDeclName() && Record->isDefinition() &&
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
//
|
||||
// Tests explicit instantiation of templates.
|
||||
template<typename T, typename U = T> class X0 { };
|
||||
|
||||
namespace N {
|
||||
template<typename T, typename U = T> class X1 { };
|
||||
}
|
||||
|
||||
template class X0<int, float>;
|
||||
template class X0<int>;
|
||||
|
||||
template class N::X1<int>;
|
||||
template class ::N::X1<int, float>;
|
||||
|
||||
using namespace N;
|
||||
template class X1<float>;
|
||||
|
||||
template class X0<double> { }; // expected-error{{explicit specialization}}
|
|
@ -2053,11 +2053,11 @@ welcome!</p>
|
|||
</tr>
|
||||
<tr>
|
||||
<td> 14.7.2 [temp.explicit]</td>
|
||||
<td class="basic" align="center"></td>
|
||||
<td class="basic" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td></td>
|
||||
<td>Function templates cannot be instantiated</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 14.7.3 [temp.expl.spec]</td>
|
||||
|
|
Loading…
Reference in New Issue