#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "RAIIObjectsForParser.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTConsumer.h"
using namespace clang;
Decl *
Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
return ParseExplicitInstantiation(Context,
SourceLocation(), ConsumeToken(),
DeclEnd, AS);
}
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
AccessAttrs);
}
namespace {
class TemplateParameterDepthCounter {
unsigned &Depth;
unsigned AddedLevels;
public:
explicit TemplateParameterDepthCounter(unsigned &Depth)
: Depth(Depth), AddedLevels(0) { }
~TemplateParameterDepthCounter() {
Depth -= AddedLevels;
}
void operator++() {
++Depth;
++AddedLevels;
}
operator unsigned() const { return Depth; }
};
}
Decl *
Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
"Token does not start a template declaration.");
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
ParsingDeclRAIIObject
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
bool isSpecialization = true;
bool LastParamListWasEmpty = false;
TemplateParameterLists ParamLists;
TemplateParameterDepthCounter Depth(TemplateParameterDepth);
do {
SourceLocation ExportLoc;
if (Tok.is(tok::kw_export)) {
ExportLoc = ConsumeToken();
}
SourceLocation TemplateLoc;
if (Tok.is(tok::kw_template)) {
TemplateLoc = ConsumeToken();
} else {
Diag(Tok.getLocation(), diag::err_expected_template);
return 0;
}
SourceLocation LAngleLoc, RAngleLoc;
SmallVector<Decl*, 4> TemplateParams;
if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc,
RAngleLoc)) {
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return 0;
}
ParamLists.push_back(
Actions.ActOnTemplateParameterList(Depth, ExportLoc,
TemplateLoc, LAngleLoc,
TemplateParams.data(),
TemplateParams.size(), RAngleLoc));
if (!TemplateParams.empty()) {
isSpecialization = false;
++Depth;
} else {
LastParamListWasEmpty = true;
}
} while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(&ParamLists,
isSpecialization,
LastParamListWasEmpty),
ParsingTemplateParams,
DeclEnd, AS, AccessAttrs);
}
Decl *
Parser::ParseSingleDeclarationAfterTemplate(
unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromTParams,
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
if (Context == Declarator::MemberContext) {
ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
&DiagsFromTParams);
return 0;
}
ParsedAttributesWithRange prefixAttrs(AttrFactory);
MaybeParseCXX0XAttributes(prefixAttrs);
if (Tok.is(tok::kw_using))
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
prefixAttrs);
ParsingDeclSpec DS(*this, &DiagsFromTParams);
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
ProhibitAttributes(prefixAttrs);
else
DS.takeAttributesFrom(prefixAttrs);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
DeclEnd = ConsumeToken();
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
DS.complete(Decl);
return Decl;
}
ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context);
ParseDeclarator(DeclaratorInfo);
if (!DeclaratorInfo.hasName()) {
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return 0;
}
LateParsedAttrList LateParsedAttrs;
if (DeclaratorInfo.isFunctionDeclarator())
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
if (isDeclarationAfterDeclarator()) {
Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
TemplateInfo);
if (Tok.is(tok::comma)) {
Diag(Tok, diag::err_multiple_template_declarators)
<< (int)TemplateInfo.Kind;
SkipUntil(tok::semi, true, false);
return ThisDecl;
}
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
if (LateParsedAttrs.size() > 0)
ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
DeclaratorInfo.complete(ThisDecl);
return ThisDecl;
}
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
DS.ClearStorageClassSpecs();
}
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
&LateParsedAttrs);
}
if (DeclaratorInfo.isFunctionDeclarator())
Diag(Tok, diag::err_expected_fn_body);
else
Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
SkipUntil(tok::semi);
return 0;
}
bool Parser::ParseTemplateParameters(unsigned Depth,
SmallVectorImpl<Decl*> &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc) {
if (!Tok.is(tok::less)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
return true;
}
LAngleLoc = ConsumeToken();
bool Failed = false;
if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
Failed = ParseTemplateParameterList(Depth, TemplateParams);
if (Tok.is(tok::greatergreater)) {
Tok.setKind(tok::greater);
RAngleLoc = Tok.getLocation();
Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
} else if (Tok.is(tok::greater))
RAngleLoc = ConsumeToken();
else if (Failed) {
Diag(Tok.getLocation(), diag::err_expected_greater);
return true;
}
return false;
}
bool
Parser::ParseTemplateParameterList(unsigned Depth,
SmallVectorImpl<Decl*> &TemplateParams) {
while (1) {
if (Decl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
TemplateParams.push_back(TmpParam);
} else {
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
if (Tok.is(tok::comma)) {
ConsumeToken();
} else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
break;
} else {
Diag(Tok.getLocation(), diag::err_expected_comma_greater);
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
return false;
}
}
return true;
}
bool Parser::isStartOfTemplateTypeParameter() {
if (Tok.is(tok::kw_class)) {
switch (NextToken().getKind()) {
case tok::equal:
case tok::comma:
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
return true;
case tok::identifier:
break;
default:
return false;
}
switch (GetLookAheadToken(2).getKind()) {
case tok::equal:
case tok::comma:
case tok::greater:
case tok::greatergreater:
return true;
default:
return false;
}
}
if (Tok.isNot(tok::kw_typename))
return false;
Token Next = NextToken();
if (Next.getKind() == tok::identifier)
Next = GetLookAheadToken(2);
switch (Next.getKind()) {
case tok::equal:
case tok::comma:
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
return true;
default:
return false;
}
}
Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
return ParseNonTypeTemplateParameter(Depth, Position);
}
Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
"A type-parameter starts with 'class' or 'typename'");
bool TypenameKeyword = Tok.is(tok::kw_typename);
SourceLocation KeyLoc = ConsumeToken();
bool Ellipsis = false;
SourceLocation EllipsisLoc;
if (Tok.is(tok::ellipsis)) {
Ellipsis = true;
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
getLangOpts().CPlusPlus0x
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
SourceLocation NameLoc;
IdentifierInfo* ParamName = 0;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
} else {
Diag(Tok.getLocation(), diag::err_expected_ident);
return 0;
}
SourceLocation EqualLoc;
ParsedType DefaultArg;
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
DefaultArg = ParseTypeName(0,
Declarator::TemplateTypeArgContext).get();
}
return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis,
EllipsisLoc, KeyLoc, ParamName, NameLoc,
Depth, Position, EqualLoc, DefaultArg);
}
Decl *
Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
SourceLocation TemplateLoc = ConsumeToken();
SmallVector<Decl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
{
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
RAngleLoc)) {
return 0;
}
}
if (!Tok.is(tok::kw_class)) {
bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct);
const Token& Next = Replace ? NextToken() : Tok;
if (Next.is(tok::identifier) || Next.is(tok::comma) ||
Next.is(tok::greater) || Next.is(tok::greatergreater) ||
Next.is(tok::ellipsis))
Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
<< (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
: FixItHint::CreateInsertion(Tok.getLocation(), "class "));
else
Diag(Tok.getLocation(), diag::err_class_on_template_template_param);
if (Replace)
ConsumeToken();
} else
ConsumeToken();
SourceLocation EllipsisLoc;
if (Tok.is(tok::ellipsis)) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
getLangOpts().CPlusPlus0x
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
SourceLocation NameLoc;
IdentifierInfo* ParamName = 0;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
} else {
Diag(Tok.getLocation(), diag::err_expected_ident);
return 0;
}
TemplateParameterList *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
TemplateParams.data(),
TemplateParams.size(),
RAngleLoc);
SourceLocation EqualLoc;
ParsedTemplateArgument DefaultArg;
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
DefaultArg = ParseTemplateTemplateArgument();
if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
}
return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc,
ParamList, EllipsisLoc,
ParamName, NameLoc, Depth,
Position, EqualLoc, DefaultArg);
}
Decl *
Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
ParseDeclarator(ParamDecl);
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
return 0;
}
SourceLocation EqualLoc;
ExprResult DefaultArg;
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
DefaultArg = ParseAssignmentExpression();
if (DefaultArg.isInvalid())
SkipUntil(tok::comma, tok::greater, true, true);
}
return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
Depth, Position, EqualLoc,
DefaultArg.take());
}
bool
Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
const CXXScopeSpec &SS,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc) {
assert(Tok.is(tok::less) && "Must have already parsed the template-name");
LAngleLoc = ConsumeToken();
bool Invalid = false;
{
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
Invalid = ParseTemplateArgumentList(TemplateArgs);
if (Invalid) {
SkipUntil(tok::greater, true, !ConsumeLastToken);
return true;
}
}
tok::TokenKind RemainingToken;
const char *ReplacementStr = "> >";
switch (Tok.getKind()) {
default:
Diag(Tok.getLocation(), diag::err_expected_greater);
return true;
case tok::greater:
RAngleLoc = Tok.getLocation();
if (ConsumeLastToken)
ConsumeToken();
return false;
case tok::greatergreater:
RemainingToken = tok::greater;
break;
case tok::greatergreatergreater:
RemainingToken = tok::greatergreater;
break;
case tok::greaterequal:
RemainingToken = tok::equal;
ReplacementStr = "> =";
break;
case tok::greatergreaterequal:
RemainingToken = tok::greaterequal;
break;
}
RAngleLoc = Tok.getLocation();
CharSourceRange ReplacementRange =
CharSourceRange::getCharRange(RAngleLoc,
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
getLangOpts()));
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
ReplacementStr);
FixItHint Hint2;
Token Next = NextToken();
if ((RemainingToken == tok::greater ||
RemainingToken == tok::greatergreater) &&
(Next.is(tok::greater) || Next.is(tok::greatergreater) ||
Next.is(tok::greatergreatergreater) || Next.is(tok::equal) ||
Next.is(tok::greaterequal) || Next.is(tok::greatergreaterequal) ||
Next.is(tok::equalequal)) &&
areTokensAdjacent(Tok, Next))
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater))
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
else if (Tok.is(tok::greaterequal))
DiagId = diag::err_right_angle_bracket_equal_needs_space;
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
areTokensAdjacent(Tok, Next)) {
ConsumeToken();
Tok.setKind(tok::equalequal);
Tok.setLength(Tok.getLength() + 1);
} else {
Tok.setKind(RemainingToken);
Tok.setLength(Tok.getLength() - 1);
}
Tok.setLocation(Lexer::AdvanceToTokenCharacter(RAngleLoc, 1,
PP.getSourceManager(),
getLangOpts()));
if (!ConsumeLastToken) {
PP.EnterToken(Tok);
Tok.setKind(tok::greater);
Tok.setLength(1);
Tok.setLocation(RAngleLoc);
}
return false;
}
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &TemplateName,
bool AllowTypeAnnotation) {
assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++");
assert(Template && Tok.is(tok::less) &&
"Parser isn't at the beginning of a template-id");
SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
bool Invalid = ParseTemplateIdAfterTemplateName(Template,
TemplateNameLoc,
SS, false, LAngleLoc,
TemplateArgs,
RAngleLoc);
if (Invalid) {
if (Tok.is(tok::greater))
ConsumeToken();
return true;
}
ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
TypeResult Type
= Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr, RAngleLoc);
if (Type.isInvalid()) {
if (Tok.is(tok::greater))
ConsumeToken();
return true;
}
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.get());
if (SS.isNotEmpty())
Tok.setLocation(SS.getBeginLoc());
else if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
else
Tok.setLocation(TemplateNameLoc);
} else {
Tok.setKind(tok::annot_template_id);
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
TemplateId->TemplateNameLoc = TemplateNameLoc;
if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
TemplateId->Name = TemplateName.Identifier;
TemplateId->Operator = OO_None;
} else {
TemplateId->Name = 0;
TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
}
TemplateId->SS = SS;
TemplateId->TemplateKWLoc = TemplateKWLoc;
TemplateId->Template = Template;
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
TemplateId->RAngleLoc = RAngleLoc;
ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
else
Tok.setLocation(TemplateNameLoc);
}
Tok.setAnnotationEndLoc(RAngleLoc);
PP.AnnotateCachedTokens(Tok);
return false;
}
void Parser::AnnotateTemplateIdTokenAsType() {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
assert((TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) &&
"Only works for type and dependent templates");
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult Type
= Actions.ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc);
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get());
if (TemplateId->SS.isNotEmpty()) Tok.setLocation(TemplateId->SS.getBeginLoc());
PP.AnnotateCachedTokens(Tok);
}
static bool isEndOfTemplateArgument(Token Tok) {
return Tok.is(tok::comma) || Tok.is(tok::greater) ||
Tok.is(tok::greatergreater);
}
ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) &&
!Tok.is(tok::annot_cxxscope))
return ParsedTemplateArgument();
CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
false);
ParsedTemplateArgument Result;
SourceLocation EllipsisLoc;
if (SS.isSet() && Tok.is(tok::kw_template)) {
SourceLocation TemplateKWLoc = ConsumeToken();
if (Tok.is(tok::identifier)) {
UnqualifiedId Name;
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
if (Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
TemplateTy Template;
if (isEndOfTemplateArgument(Tok) &&
Actions.ActOnDependentTemplateName(getCurScope(),
SS, TemplateKWLoc, Name,
ParsedType(),
false,
Template))
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
} else if (Tok.is(tok::identifier)) {
TemplateTy Template;
UnqualifiedId Name;
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
if (Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
if (isEndOfTemplateArgument(Tok)) {
bool MemberOfUnknownSpecialization;
TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
false,
Name,
ParsedType(),
false,
Template,
MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
}
}
if (EllipsisLoc.isValid() && !Result.isInvalid())
Result = Actions.ActOnPackExpansion(Result, EllipsisLoc);
return Result;
}
ParsedTemplateArgument Parser::ParseTemplateArgument() {
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
SourceLocation Loc = Tok.getLocation();
TypeResult TypeArg = ParseTypeName(0,
Declarator::TemplateTypeArgContext);
if (TypeArg.isInvalid())
return ParsedTemplateArgument();
return ParsedTemplateArgument(ParsedTemplateArgument::Type,
TypeArg.get().getAsOpaquePtr(),
Loc);
}
{
TentativeParsingAction TPA(*this);
ParsedTemplateArgument TemplateTemplateArgument
= ParseTemplateTemplateArgument();
if (!TemplateTemplateArgument.isInvalid()) {
TPA.Commit();
return TemplateTemplateArgument;
}
TPA.Revert();
}
SourceLocation Loc = Tok.getLocation();
ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
if (ExprArg.isInvalid() || !ExprArg.get())
return ParsedTemplateArgument();
return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
ExprArg.release(), Loc);
}
bool Parser::IsTemplateArgumentList(unsigned Skip) {
struct AlwaysRevertAction : TentativeParsingAction {
AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { }
~AlwaysRevertAction() { Revert(); }
} Tentative(*this);
while (Skip) {
ConsumeToken();
--Skip;
}
if (!Tok.is(tok::less))
return false;
ConsumeToken();
if (Tok.is(tok::greater))
return true;
while (isCXXDeclarationSpecifier() == TPResult::True())
ConsumeToken();
return Tok.is(tok::greater) || Tok.is(tok::comma);
}
bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
while (true) {
ParsedTemplateArgument Arg = ParseTemplateArgument();
if (Tok.is(tok::ellipsis)) {
SourceLocation EllipsisLoc = ConsumeToken();
Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
}
if (Arg.isInvalid()) {
SkipUntil(tok::comma, tok::greater, true, true);
return true;
}
TemplateArgs.push_back(Arg);
if (Tok.isNot(tok::comma)) break;
ConsumeToken();
}
return false;
}
Decl *Parser::ParseExplicitInstantiation(unsigned Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
SourceLocation &DeclEnd,
AccessSpecifier AS) {
ParsingDeclRAIIObject
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(ExternLoc,
TemplateLoc),
ParsingTemplateParams,
DeclEnd, AS);
}
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
if (TemplateParams)
return getTemplateParamsRange(TemplateParams->data(),
TemplateParams->size());
SourceRange R(TemplateLoc);
if (ExternLoc.isValid())
R.setBegin(ExternLoc);
return R;
}
void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) {
((Parser*)P)->LateTemplateParser(FD);
}
void Parser::LateTemplateParser(const FunctionDecl *FD) {
LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD];
if (LPT) {
ParseLateTemplatedFuncDef(*LPT);
return;
}
llvm_unreachable("Late templated function without associated lexed tokens");
}
void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
if(!LMT.D)
return;
FunctionDecl *FD = 0;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D))
FD = FunTmpl->getTemplatedDecl();
else
FD = cast<FunctionDecl>(LMT.D);
Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext);
SmallVector<ParseScope*, 4> TemplateParamScopeStack;
DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD);
if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope));
Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
} else {
SmallVector<DeclContext*, 4> DeclContextToReenter;
DeclContext *DD = FD->getLexicalParent();
while (DD && !DD->isTranslationUnit()) {
DeclContextToReenter.push_back(DD);
DD = DD->getLexicalParent();
}
SmallVector<DeclContext*, 4>::reverse_iterator II =
DeclContextToReenter.rbegin();
for (; II != DeclContextToReenter.rend(); ++II) {
if (ClassTemplatePartialSpecializationDecl* MD =
dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
TemplateParamScopeStack.push_back(new ParseScope(this,
Scope::TemplateParamScope));
Actions.ActOnReenterTemplateScope(getCurScope(), MD);
} else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
TemplateParamScopeStack.push_back(new ParseScope(this,
Scope::TemplateParamScope,
MD->getDescribedClassTemplate() != 0 ));
Actions.ActOnReenterTemplateScope(getCurScope(),
MD->getDescribedClassTemplate());
}
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
Actions.PushDeclContext(Actions.getCurScope(), *II);
}
TemplateParamScopeStack.push_back(new ParseScope(this,
Scope::TemplateParamScope));
Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
}
assert(!LMT.Toks.empty() && "Empty body!");
LMT.Toks.push_back(Tok);
PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
ConsumeAnyToken();
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
&& "Inline method not starting with '{', ':' or 'try'");
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD));
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(LMT.D))
Actions.ActOnStartOfFunctionDef(getCurScope(),
FunctionTemplate->getTemplatedDecl());
if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D))
Actions.ActOnStartOfFunctionDef(getCurScope(), Function);
if (Tok.is(tok::kw_try)) {
ParseFunctionTryBlock(LMT.D, FnScope);
} else {
if (Tok.is(tok::colon))
ParseConstructorInitializer(LMT.D);
else
Actions.ActOnDefaultCtorInitializers(LMT.D);
if (Tok.is(tok::l_brace)) {
ParseFunctionStatementBody(LMT.D, FnScope);
Actions.MarkAsLateParsedTemplate(FD, false);
} else
Actions.ActOnFinishFunctionBody(LMT.D, 0);
}
FnScope.Exit();
SmallVector<ParseScope*, 4>::reverse_iterator I =
TemplateParamScopeStack.rbegin();
for (; I != TemplateParamScopeStack.rend(); ++I)
delete *I;
DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D);
if (grp)
Actions.getASTConsumer().HandleTopLevelDecl(grp.get());
}
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
tok::TokenKind kind = Tok.getKind();
if (!ConsumeAndStoreFunctionPrologue(Toks)) {
ConsumeAndStoreUntil(tok::r_brace, Toks, false);
}
if (kind == tok::kw_try) {
while (Tok.is(tok::kw_catch)) {
ConsumeAndStoreUntil(tok::l_brace, Toks, false);
ConsumeAndStoreUntil(tok::r_brace, Toks, false);
}
}
}