2013-06-09 03:39:00 +08:00
|
|
|
//===--- ParseTemplate.cpp - Template Parsing -----------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-06-09 03:39:00 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements parsing of C++ templates.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-05-12 07:09:06 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2013-06-09 03:39:00 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2016-07-19 03:02:11 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2017-03-23 23:11:07 +08:00
|
|
|
#include "clang/Parse/RAIIObjectsForParser.h"
|
2013-06-09 03:39:00 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
|
|
|
#include "clang/Sema/ParsedTemplate.h"
|
|
|
|
#include "clang/Sema/Scope.h"
|
|
|
|
using namespace clang;
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a template declaration, explicit instantiation, or
|
2013-06-09 03:39:00 +08:00
|
|
|
/// explicit specialization.
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *Parser::ParseDeclarationStartingWithTemplate(
|
|
|
|
DeclaratorContext Context, SourceLocation &DeclEnd,
|
|
|
|
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
|
2013-06-09 03:39:00 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
|
2018-07-13 05:09:05 +08:00
|
|
|
return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(),
|
|
|
|
DeclEnd, AccessAttrs, AS);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
2018-07-13 05:09:05 +08:00
|
|
|
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs,
|
|
|
|
AS);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a template declaration or an explicit specialization.
|
2013-06-09 03:39:00 +08:00
|
|
|
///
|
|
|
|
/// Template declarations include one or more template parameter lists
|
|
|
|
/// and either the function or class template declaration. Explicit
|
|
|
|
/// specializations contain one or more 'template < >' prefixes
|
|
|
|
/// followed by a (possibly templated) declaration. Since the
|
|
|
|
/// syntactic form of both features is nearly identical, we parse all
|
|
|
|
/// of the template headers together and let semantic analysis sort
|
|
|
|
/// the declarations from the explicit specializations.
|
|
|
|
///
|
|
|
|
/// template-declaration: [C++ temp]
|
|
|
|
/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
|
|
|
|
///
|
|
|
|
/// explicit-specialization: [ C++ temp.expl.spec]
|
|
|
|
/// 'template' '<' '>' declaration
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *Parser::ParseTemplateDeclarationOrSpecialization(
|
|
|
|
DeclaratorContext Context, SourceLocation &DeclEnd,
|
|
|
|
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
|
2015-06-18 18:59:26 +08:00
|
|
|
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
|
2013-06-09 03:39:00 +08:00
|
|
|
"Token does not start a template declaration.");
|
|
|
|
|
|
|
|
// Enter template-parameter scope.
|
|
|
|
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
|
|
|
|
|
|
|
|
// Tell the action that names should be checked in the context of
|
|
|
|
// the declaration to come.
|
|
|
|
ParsingDeclRAIIObject
|
|
|
|
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
|
|
|
|
|
|
|
|
// Parse multiple levels of template headers within this template
|
|
|
|
// parameter scope, e.g.,
|
|
|
|
//
|
|
|
|
// template<typename T>
|
|
|
|
// template<typename U>
|
|
|
|
// class A<T>::B { ... };
|
|
|
|
//
|
|
|
|
// We parse multiple levels non-recursively so that we can build a
|
|
|
|
// single data structure containing all of the template parameter
|
|
|
|
// lists to easily differentiate between the case above and:
|
|
|
|
//
|
|
|
|
// template<typename T>
|
|
|
|
// class A {
|
|
|
|
// template<typename U> class B;
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// In the first case, the action for declaring A<T>::B receives
|
|
|
|
// both template parameter lists. In the second case, the action for
|
|
|
|
// defining A<T>::B receives just the inner template parameter list
|
|
|
|
// (and retrieves the outer template parameter list from its
|
|
|
|
// context).
|
|
|
|
bool isSpecialization = true;
|
|
|
|
bool LastParamListWasEmpty = false;
|
|
|
|
TemplateParameterLists ParamLists;
|
|
|
|
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
|
|
|
|
|
|
|
|
do {
|
|
|
|
// Consume the 'export', if any.
|
|
|
|
SourceLocation ExportLoc;
|
2013-12-17 22:12:37 +08:00
|
|
|
TryConsumeToken(tok::kw_export, ExportLoc);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Consume the 'template', which should be here.
|
|
|
|
SourceLocation TemplateLoc;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (!TryConsumeToken(tok::kw_template, TemplateLoc)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected_template);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the '<' template-parameter-list '>'
|
|
|
|
SourceLocation LAngleLoc, RAngleLoc;
|
2017-08-26 02:24:20 +08:00
|
|
|
SmallVector<NamedDecl*, 4> TemplateParams;
|
2013-06-09 03:39:00 +08:00
|
|
|
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
|
|
|
|
TemplateParams, LAngleLoc, RAngleLoc)) {
|
2015-06-25 08:23:39 +08:00
|
|
|
// Skip until the semi-colon or a '}'.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2013-12-17 22:12:37 +08:00
|
|
|
TryConsumeToken(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 02:05:37 +08:00
|
|
|
ExprResult OptionalRequiresClauseConstraintER;
|
2013-06-09 03:39:00 +08:00
|
|
|
if (!TemplateParams.empty()) {
|
|
|
|
isSpecialization = false;
|
|
|
|
++CurTemplateDepthTracker;
|
2015-06-25 08:23:39 +08:00
|
|
|
|
|
|
|
if (TryConsumeToken(tok::kw_requires)) {
|
2016-04-30 02:05:37 +08:00
|
|
|
OptionalRequiresClauseConstraintER =
|
2015-06-25 08:23:39 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
|
2016-04-30 02:05:37 +08:00
|
|
|
if (!OptionalRequiresClauseConstraintER.isUsable()) {
|
2015-06-25 08:23:39 +08:00
|
|
|
// Skip until the semi-colon or a '}'.
|
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
|
|
|
TryConsumeToken(tok::semi);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
} else {
|
|
|
|
LastParamListWasEmpty = true;
|
|
|
|
}
|
2016-04-30 02:05:37 +08:00
|
|
|
|
|
|
|
ParamLists.push_back(Actions.ActOnTemplateParameterList(
|
|
|
|
CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc,
|
|
|
|
TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get()));
|
2015-06-18 18:59:26 +08:00
|
|
|
} while (Tok.isOneOf(tok::kw_export, tok::kw_template));
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2016-04-29 10:24:14 +08:00
|
|
|
unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;
|
|
|
|
ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
|
|
|
|
|
2018-04-26 08:42:40 +08:00
|
|
|
// Parse the actual template declaration.
|
2018-07-13 05:09:05 +08:00
|
|
|
return ParseSingleDeclarationAfterTemplate(
|
|
|
|
Context,
|
|
|
|
ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
|
|
|
|
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a single declaration that declares a template,
|
2013-06-09 03:39:00 +08:00
|
|
|
/// template specialization, or explicit instantiation of a template.
|
|
|
|
///
|
|
|
|
/// \param DeclEnd will receive the source location of the last token
|
|
|
|
/// within this declaration.
|
|
|
|
///
|
|
|
|
/// \param AS the access specifier associated with this
|
|
|
|
/// declaration. Will be AS_none for namespace-scope declarations.
|
|
|
|
///
|
|
|
|
/// \returns the new declaration.
|
2018-07-13 05:09:05 +08:00
|
|
|
Decl *Parser::ParseSingleDeclarationAfterTemplate(
|
|
|
|
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
|
|
|
|
ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd,
|
|
|
|
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
|
2013-06-09 03:39:00 +08:00
|
|
|
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
|
|
|
|
"Template information required");
|
|
|
|
|
2014-08-05 04:28:35 +08:00
|
|
|
if (Tok.is(tok::kw_static_assert)) {
|
|
|
|
// A static_assert declaration may not be templated.
|
|
|
|
Diag(Tok.getLocation(), diag::err_templated_invalid_declaration)
|
|
|
|
<< TemplateInfo.getSourceRange();
|
|
|
|
// Parse the static_assert declaration to improve error recovery.
|
|
|
|
return ParseStaticAssertDeclaration(DeclEnd);
|
|
|
|
}
|
|
|
|
|
2017-12-29 13:41:00 +08:00
|
|
|
if (Context == DeclaratorContext::MemberContext) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// We are parsing a member template.
|
|
|
|
ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
|
|
|
|
&DiagsFromTParams);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ParsedAttributesWithRange prefixAttrs(AttrFactory);
|
|
|
|
MaybeParseCXX11Attributes(prefixAttrs);
|
|
|
|
|
2016-12-16 08:58:48 +08:00
|
|
|
if (Tok.is(tok::kw_using)) {
|
2017-09-08 17:31:13 +08:00
|
|
|
auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
|
|
|
prefixAttrs);
|
|
|
|
if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
|
|
|
|
return nullptr;
|
|
|
|
return usingDeclPtr.get().getSingleDecl();
|
2016-12-16 08:58:48 +08:00
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Parse the declaration specifiers, stealing any diagnostics from
|
|
|
|
// the template parameters.
|
|
|
|
ParsingDeclSpec DS(*this, &DiagsFromTParams);
|
|
|
|
|
2018-04-26 08:42:40 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
|
2013-06-09 03:39:00 +08:00
|
|
|
getDeclSpecContextFromDeclaratorContext(Context));
|
|
|
|
|
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ProhibitAttributes(prefixAttrs);
|
|
|
|
DeclEnd = ConsumeToken();
|
2016-01-29 03:25:00 +08:00
|
|
|
RecordDecl *AnonRecord = nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
|
|
|
|
getCurScope(), AS, DS,
|
|
|
|
TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
|
|
|
|
: MultiTemplateParamsArg(),
|
2016-01-29 03:25:00 +08:00
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation,
|
|
|
|
AnonRecord);
|
|
|
|
assert(!AnonRecord &&
|
|
|
|
"Anonymous unions/structs should not be valid with template");
|
2013-06-09 03:39:00 +08:00
|
|
|
DS.complete(Decl);
|
|
|
|
return Decl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move the attributes from the prefix into the DS.
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
|
|
|
ProhibitAttributes(prefixAttrs);
|
|
|
|
else
|
|
|
|
DS.takeAttributesFrom(prefixAttrs);
|
|
|
|
|
|
|
|
// Parse the declarator.
|
2017-12-29 13:41:00 +08:00
|
|
|
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
|
2013-06-09 03:39:00 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
// Error parsing the declarator?
|
|
|
|
if (!DeclaratorInfo.hasName()) {
|
|
|
|
// If so, skip until the semi-colon or a }.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
LateParsedAttrList LateParsedAttrs(true);
|
|
|
|
if (DeclaratorInfo.isFunctionDeclarator())
|
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
|
|
|
|
|
|
|
|
if (DeclaratorInfo.isFunctionDeclarator() &&
|
|
|
|
isStartOfFunctionDefinition(DeclaratorInfo)) {
|
2014-12-16 07:16:32 +08:00
|
|
|
|
|
|
|
// Function definitions are only allowed at file scope and in C++ classes.
|
|
|
|
// The C++ inline method definition case is handled elsewhere, so we only
|
|
|
|
// need to handle the file scope definition case.
|
2017-12-29 13:41:00 +08:00
|
|
|
if (Context != DeclaratorContext::FileContext) {
|
2014-12-16 07:16:32 +08:00
|
|
|
Diag(Tok, diag::err_function_definition_not_allowed);
|
|
|
|
SkipMalformedDecl();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
|
|
|
// Recover by ignoring the 'typedef'. This was probably supposed to be
|
|
|
|
// the 'typename' keyword, which we should have already suggested adding
|
|
|
|
// if it's appropriate.
|
|
|
|
Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
|
|
|
|
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
|
|
|
|
DS.ClearStorageClassSpecs();
|
|
|
|
}
|
2013-06-21 08:08:46 +08:00
|
|
|
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
|
2017-12-30 12:15:27 +08:00
|
|
|
if (DeclaratorInfo.getName().getKind() !=
|
|
|
|
UnqualifiedIdKind::IK_TemplateId) {
|
2013-06-21 08:08:46 +08:00
|
|
|
// If the declarator-id is not a template-id, issue a diagnostic and
|
|
|
|
// recover by ignoring the 'template' keyword.
|
|
|
|
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
|
2013-08-06 09:03:05 +08:00
|
|
|
return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
|
|
|
|
&LateParsedAttrs);
|
2013-06-21 08:08:46 +08:00
|
|
|
} else {
|
|
|
|
SourceLocation LAngleLoc
|
|
|
|
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
|
2013-08-06 09:03:05 +08:00
|
|
|
Diag(DeclaratorInfo.getIdentifierLoc(),
|
2013-06-21 08:08:46 +08:00
|
|
|
diag::err_explicit_instantiation_with_definition)
|
2013-08-06 09:03:05 +08:00
|
|
|
<< SourceRange(TemplateInfo.TemplateLoc)
|
|
|
|
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
|
2013-06-21 08:08:46 +08:00
|
|
|
|
2013-08-06 09:03:05 +08:00
|
|
|
// Recover as if it were an explicit specialization.
|
2013-06-22 21:56:11 +08:00
|
|
|
TemplateParameterLists FakedParamLists;
|
2013-08-06 09:03:05 +08:00
|
|
|
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
|
2015-12-25 07:58:25 +08:00
|
|
|
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
|
2016-04-30 02:05:37 +08:00
|
|
|
LAngleLoc, nullptr));
|
2013-06-21 08:08:46 +08:00
|
|
|
|
2013-08-06 09:03:05 +08:00
|
|
|
return ParseFunctionDefinition(
|
|
|
|
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
|
|
|
|
/*isSpecialization=*/true,
|
|
|
|
/*LastParamListWasEmpty=*/true),
|
|
|
|
&LateParsedAttrs);
|
2013-06-21 08:08:46 +08:00
|
|
|
}
|
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
|
2013-08-06 09:03:05 +08:00
|
|
|
&LateParsedAttrs);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse this declaration.
|
|
|
|
Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
|
|
|
|
TemplateInfo);
|
|
|
|
|
|
|
|
if (Tok.is(tok::comma)) {
|
|
|
|
Diag(Tok, diag::err_multiple_template_declarators)
|
|
|
|
<< (int)TemplateInfo.Kind;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi);
|
2013-06-09 03:39:00 +08:00
|
|
|
return ThisDecl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Eat the semi colon after the declaration.
|
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
|
|
|
|
if (LateParsedAttrs.size() > 0)
|
|
|
|
ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
|
|
|
|
DeclaratorInfo.complete(ThisDecl);
|
|
|
|
return ThisDecl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
|
|
|
|
/// angle brackets. Depth is the depth of this template-parameter-list, which
|
|
|
|
/// is the number of template headers directly enclosing this template header.
|
|
|
|
/// TemplateParams is the current list of template parameters we're building.
|
|
|
|
/// The template parameter we parse will be added to this list. LAngleLoc and
|
|
|
|
/// RAngleLoc will receive the positions of the '<' and '>', respectively,
|
|
|
|
/// that enclose this template parameter list.
|
|
|
|
///
|
|
|
|
/// \returns true if an error occurred, false otherwise.
|
2017-08-26 02:24:20 +08:00
|
|
|
bool Parser::ParseTemplateParameters(
|
|
|
|
unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams,
|
|
|
|
SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// Get the template parameter list.
|
2013-12-17 22:12:37 +08:00
|
|
|
if (!TryConsumeToken(tok::less, LAngleLoc)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to parse the template parameter list.
|
|
|
|
bool Failed = false;
|
|
|
|
if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
|
|
|
|
Failed = ParseTemplateParameterList(Depth, TemplateParams);
|
|
|
|
|
|
|
|
if (Tok.is(tok::greatergreater)) {
|
|
|
|
// No diagnostic required here: a template-parameter-list can only be
|
|
|
|
// followed by a declaration or, for a template template parameter, the
|
|
|
|
// 'class' keyword. Therefore, the second '>' will be diagnosed later.
|
|
|
|
// This matters for elegant diagnosis of:
|
|
|
|
// template<template<typename>> struct S;
|
|
|
|
Tok.setKind(tok::greater);
|
|
|
|
RAngleLoc = Tok.getLocation();
|
|
|
|
Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
|
2014-01-01 11:08:43 +08:00
|
|
|
} else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected) << tok::greater;
|
2013-06-09 03:39:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateParameterList - Parse a template parameter list. If
|
|
|
|
/// the parsing fails badly (i.e., closing bracket was left out), this
|
|
|
|
/// will try to put the token stream in a reasonable position (closing
|
|
|
|
/// a statement, etc.) and return false.
|
|
|
|
///
|
|
|
|
/// template-parameter-list: [C++ temp]
|
|
|
|
/// template-parameter
|
|
|
|
/// template-parameter-list ',' template-parameter
|
|
|
|
bool
|
2017-12-29 13:41:00 +08:00
|
|
|
Parser::ParseTemplateParameterList(const unsigned Depth,
|
2017-08-26 02:24:20 +08:00
|
|
|
SmallVectorImpl<NamedDecl*> &TemplateParams) {
|
2013-06-09 03:39:00 +08:00
|
|
|
while (1) {
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-12-24 02:56:34 +08:00
|
|
|
if (NamedDecl *TmpParam
|
2013-06-09 03:39:00 +08:00
|
|
|
= ParseTemplateParameter(Depth, TemplateParams.size())) {
|
2017-12-24 03:27:07 +08:00
|
|
|
TemplateParams.push_back(TmpParam);
|
2013-06-09 03:39:00 +08:00
|
|
|
} else {
|
|
|
|
// If we failed to parse a template parameter, skip until we find
|
|
|
|
// a comma or closing brace.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::greater, tok::greatergreater,
|
|
|
|
StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Did we find a comma or the end of the template parameter list?
|
|
|
|
if (Tok.is(tok::comma)) {
|
|
|
|
ConsumeToken();
|
2015-06-18 18:59:26 +08:00
|
|
|
} else if (Tok.isOneOf(tok::greater, tok::greatergreater)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// Don't consume this... that's done by template parser.
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Somebody probably forgot to close the template. Skip ahead and
|
|
|
|
// try to get out of the expression. This error is currently
|
|
|
|
// subsumed by whatever goes on in ParseTemplateParameter.
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected_comma_greater);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::greater, tok::greatergreater,
|
|
|
|
StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether the parser is at the start of a template
|
2013-06-09 03:39:00 +08:00
|
|
|
/// type parameter.
|
|
|
|
bool Parser::isStartOfTemplateTypeParameter() {
|
|
|
|
if (Tok.is(tok::kw_class)) {
|
|
|
|
// "class" may be the start of an elaborated-type-specifier or a
|
|
|
|
// type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
|
|
|
|
switch (NextToken().getKind()) {
|
|
|
|
case tok::equal:
|
|
|
|
case tok::comma:
|
|
|
|
case tok::greater:
|
|
|
|
case tok::greatergreater:
|
|
|
|
case tok::ellipsis:
|
|
|
|
return true;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
case tok::identifier:
|
2018-07-31 03:24:48 +08:00
|
|
|
// This may be either a type-parameter or an elaborated-type-specifier.
|
2013-06-09 03:39:00 +08:00
|
|
|
// We have to look further.
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
switch (GetLookAheadToken(2).getKind()) {
|
|
|
|
case tok::equal:
|
|
|
|
case tok::comma:
|
|
|
|
case tok::greater:
|
|
|
|
case tok::greatergreater:
|
|
|
|
return true;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-18 03:43:40 +08:00
|
|
|
// 'typedef' is a reasonably-common typo/thinko for 'typename', and is
|
|
|
|
// ill-formed otherwise.
|
|
|
|
if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
|
2013-06-09 03:39:00 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// C++ [temp.param]p2:
|
|
|
|
// There is no semantic difference between class and typename in a
|
|
|
|
// template-parameter. typename followed by an unqualified-id
|
|
|
|
// names a template type parameter. typename followed by a
|
|
|
|
// qualified-id denotes the type in a non-type
|
|
|
|
// parameter-declaration.
|
|
|
|
Token Next = NextToken();
|
|
|
|
|
|
|
|
// If we have an identifier, skip over it.
|
|
|
|
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;
|
|
|
|
|
2018-08-18 03:43:40 +08:00
|
|
|
case tok::kw_typename:
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_class:
|
|
|
|
// These indicate that a comma was missed after a type parameter, not that
|
|
|
|
// we have found a non-type parameter.
|
|
|
|
return true;
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
|
|
|
|
///
|
|
|
|
/// template-parameter: [C++ temp.param]
|
|
|
|
/// type-parameter
|
|
|
|
/// parameter-declaration
|
|
|
|
///
|
|
|
|
/// type-parameter: (see below)
|
|
|
|
/// 'class' ...[opt] identifier[opt]
|
|
|
|
/// 'class' identifier[opt] '=' type-id
|
|
|
|
/// 'typename' ...[opt] identifier[opt]
|
|
|
|
/// 'typename' identifier[opt] '=' type-id
|
2018-07-31 03:24:48 +08:00
|
|
|
/// 'template' '<' template-parameter-list '>'
|
2013-06-09 03:39:00 +08:00
|
|
|
/// 'class' ...[opt] identifier[opt]
|
|
|
|
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
|
|
|
|
/// = id-expression
|
2017-12-24 02:56:34 +08:00
|
|
|
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
|
2018-08-18 03:43:40 +08:00
|
|
|
if (isStartOfTemplateTypeParameter()) {
|
|
|
|
// Is there just a typo in the input code? ('typedef' instead of 'typename')
|
|
|
|
if (Tok.is(tok::kw_typedef)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2018-08-18 03:43:40 +08:00
|
|
|
Diag(Tok.getLocation(), diag::note_meant_to_use_typename)
|
|
|
|
<< FixItHint::CreateReplacement(CharSourceRange::getCharRange(
|
|
|
|
Tok.getLocation(), Tok.getEndLoc()),
|
|
|
|
"typename");
|
2018-02-08 22:37:58 +08:00
|
|
|
|
2018-08-18 03:43:40 +08:00
|
|
|
Tok.setKind(tok::kw_typename);
|
|
|
|
}
|
2018-02-08 22:37:58 +08:00
|
|
|
|
|
|
|
return ParseTypeParameter(Depth, Position);
|
|
|
|
}
|
|
|
|
|
2018-08-18 03:43:40 +08:00
|
|
|
if (Tok.is(tok::kw_template))
|
|
|
|
return ParseTemplateTemplateParameter(Depth, Position);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If it's none of the above, then it must be a parameter declaration.
|
|
|
|
// NOTE: This will pick up errors in the closure of the template parameter
|
|
|
|
// list (e.g., template < ; Check here to implement >> style closures.
|
|
|
|
return ParseNonTypeTemplateParameter(Depth, Position);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
|
|
|
|
/// Other kinds of template parameters are parsed in
|
|
|
|
/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
|
|
|
|
///
|
|
|
|
/// type-parameter: [C++ temp.param]
|
|
|
|
/// 'class' ...[opt][C++0x] identifier[opt]
|
|
|
|
/// 'class' identifier[opt] '=' type-id
|
|
|
|
/// 'typename' ...[opt][C++0x] identifier[opt]
|
|
|
|
/// 'typename' identifier[opt] '=' type-id
|
2017-12-24 02:56:34 +08:00
|
|
|
NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
|
2015-06-18 18:59:26 +08:00
|
|
|
assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) &&
|
2013-06-09 03:39:00 +08:00
|
|
|
"A type-parameter starts with 'class' or 'typename'");
|
|
|
|
|
|
|
|
// Consume the 'class' or 'typename' keyword.
|
|
|
|
bool TypenameKeyword = Tok.is(tok::kw_typename);
|
|
|
|
SourceLocation KeyLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Grab the ellipsis (if given).
|
|
|
|
SourceLocation EllipsisLoc;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(EllipsisLoc,
|
|
|
|
getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_variadic_templates
|
|
|
|
: diag::ext_variadic_templates);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab the template parameter name (if given)
|
|
|
|
SourceLocation NameLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *ParamName = nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
ParamName = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
2015-06-18 18:59:26 +08:00
|
|
|
} else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
|
|
|
|
tok::greatergreater)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// Unnamed template parameter. Don't have to do anything here, just
|
|
|
|
// don't consume this token.
|
|
|
|
} else {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2014-06-06 10:58:59 +08:00
|
|
|
// Recover from misplaced ellipsis.
|
|
|
|
bool AlreadyHasEllipsis = EllipsisLoc.isValid();
|
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
|
|
|
|
DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// Grab a default argument (if available).
|
|
|
|
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
|
|
|
|
// we introduce the type parameter into the local scope.
|
|
|
|
SourceLocation EqualLoc;
|
|
|
|
ParsedType DefaultArg;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (TryConsumeToken(tok::equal, EqualLoc))
|
2014-05-21 14:02:52 +08:00
|
|
|
DefaultArg = ParseTypeName(/*Range=*/nullptr,
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclaratorContext::TemplateTypeArgContext).get();
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2014-06-06 10:58:59 +08:00
|
|
|
return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc,
|
|
|
|
KeyLoc, ParamName, NameLoc, Depth, Position,
|
|
|
|
EqualLoc, DefaultArg);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateTemplateParameter - Handle the parsing of template
|
|
|
|
/// template parameters.
|
|
|
|
///
|
|
|
|
/// type-parameter: [C++ temp.param]
|
2014-06-16 23:51:22 +08:00
|
|
|
/// 'template' '<' template-parameter-list '>' type-parameter-key
|
2013-06-09 03:39:00 +08:00
|
|
|
/// ...[opt] identifier[opt]
|
2014-06-16 23:51:22 +08:00
|
|
|
/// 'template' '<' template-parameter-list '>' type-parameter-key
|
|
|
|
/// identifier[opt] = id-expression
|
|
|
|
/// type-parameter-key:
|
|
|
|
/// 'class'
|
|
|
|
/// 'typename' [C++1z]
|
2017-12-24 02:56:34 +08:00
|
|
|
NamedDecl *
|
2013-06-09 03:39:00 +08:00
|
|
|
Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
|
|
|
|
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
|
|
|
|
|
|
|
|
// Handle the template <...> part.
|
|
|
|
SourceLocation TemplateLoc = ConsumeToken();
|
2017-08-26 02:24:20 +08:00
|
|
|
SmallVector<NamedDecl*,8> TemplateParams;
|
2013-06-09 03:39:00 +08:00
|
|
|
SourceLocation LAngleLoc, RAngleLoc;
|
|
|
|
{
|
|
|
|
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
|
|
|
|
if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
|
|
|
|
RAngleLoc)) {
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-16 23:51:22 +08:00
|
|
|
// Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
|
2013-06-09 03:39:00 +08:00
|
|
|
// Generate a meaningful error if the user forgot to put class before the
|
|
|
|
// identifier, comma, or greater. Provide a fixit if the identifier, comma,
|
2014-06-16 23:51:22 +08:00
|
|
|
// or greater appear immediately or after 'struct'. In the latter case,
|
|
|
|
// replace the keyword with 'class'.
|
2013-12-17 22:12:37 +08:00
|
|
|
if (!TryConsumeToken(tok::kw_class)) {
|
2015-06-18 18:59:26 +08:00
|
|
|
bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct);
|
2014-06-16 23:51:22 +08:00
|
|
|
const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok;
|
|
|
|
if (Tok.is(tok::kw_typename)) {
|
|
|
|
Diag(Tok.getLocation(),
|
2017-12-05 04:27:34 +08:00
|
|
|
getLangOpts().CPlusPlus17
|
2014-08-19 23:55:55 +08:00
|
|
|
? diag::warn_cxx14_compat_template_template_param_typename
|
2014-06-16 23:51:22 +08:00
|
|
|
: diag::ext_template_template_param_typename)
|
2017-12-05 04:27:34 +08:00
|
|
|
<< (!getLangOpts().CPlusPlus17
|
2014-06-16 23:51:22 +08:00
|
|
|
? FixItHint::CreateReplacement(Tok.getLocation(), "class")
|
|
|
|
: FixItHint());
|
2015-06-18 18:59:26 +08:00
|
|
|
} else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater,
|
|
|
|
tok::greatergreater, tok::ellipsis)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
|
|
|
|
<< (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
|
|
|
|
: FixItHint::CreateInsertion(Tok.getLocation(), "class "));
|
2014-06-16 23:51:22 +08:00
|
|
|
} else
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_class_on_template_template_param);
|
|
|
|
|
|
|
|
if (Replace)
|
|
|
|
ConsumeToken();
|
2013-12-17 22:12:37 +08:00
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Parse the ellipsis, if given.
|
|
|
|
SourceLocation EllipsisLoc;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
|
2013-06-09 03:39:00 +08:00
|
|
|
Diag(EllipsisLoc,
|
|
|
|
getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_variadic_templates
|
|
|
|
: diag::ext_variadic_templates);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// Get the identifier, if given.
|
|
|
|
SourceLocation NameLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *ParamName = nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
ParamName = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
2015-06-18 18:59:26 +08:00
|
|
|
} else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
|
|
|
|
tok::greatergreater)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// Unnamed template parameter. Don't have to do anything here, just
|
|
|
|
// don't consume this token.
|
|
|
|
} else {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2014-06-06 10:58:59 +08:00
|
|
|
// Recover from misplaced ellipsis.
|
|
|
|
bool AlreadyHasEllipsis = EllipsisLoc.isValid();
|
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
|
|
|
|
DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
TemplateParameterList *ParamList =
|
|
|
|
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
|
|
|
|
TemplateLoc, LAngleLoc,
|
2015-12-25 07:58:25 +08:00
|
|
|
TemplateParams,
|
2016-04-30 02:05:37 +08:00
|
|
|
RAngleLoc, nullptr);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Grab a default argument (if available).
|
|
|
|
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
|
|
|
|
// we introduce the template parameter into the local scope.
|
|
|
|
SourceLocation EqualLoc;
|
|
|
|
ParsedTemplateArgument DefaultArg;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (TryConsumeToken(tok::equal, EqualLoc)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
DefaultArg = ParseTemplateTemplateArgument();
|
|
|
|
if (DefaultArg.isInvalid()) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Diag(Tok.getLocation(),
|
2013-06-09 03:39:00 +08:00
|
|
|
diag::err_default_template_template_parameter_not_template);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::greater, tok::greatergreater,
|
|
|
|
StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
ParamList, EllipsisLoc,
|
|
|
|
ParamName, NameLoc, Depth,
|
2013-06-09 03:39:00 +08:00
|
|
|
Position, EqualLoc, DefaultArg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
|
|
|
|
/// template parameters (e.g., in "template<int Size> class array;").
|
|
|
|
///
|
|
|
|
/// template-parameter:
|
|
|
|
/// ...
|
|
|
|
/// parameter-declaration
|
2017-12-24 02:56:34 +08:00
|
|
|
NamedDecl *
|
2013-06-09 03:39:00 +08:00
|
|
|
Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
|
|
|
|
// Parse the declaration-specifiers (i.e., the type).
|
|
|
|
// FIXME: The type should probably be restricted in some way... Not all
|
|
|
|
// declarators (parts of declarators?) are accepted for parameters.
|
|
|
|
DeclSpec DS(AttrFactory);
|
2018-04-26 08:42:40 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
|
|
|
|
DeclSpecContext::DSC_template_param);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Parse this as a typename.
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator ParamDecl(DS, DeclaratorContext::TemplateParamContext);
|
2013-06-09 03:39:00 +08:00
|
|
|
ParseDeclarator(ParamDecl);
|
|
|
|
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2014-06-06 10:58:59 +08:00
|
|
|
// Recover from misplaced ellipsis.
|
|
|
|
SourceLocation EllipsisLoc;
|
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
|
|
|
|
DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, ParamDecl);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If there is a default value, parse it.
|
|
|
|
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
|
|
|
|
// we introduce the template parameter into the local scope.
|
|
|
|
SourceLocation EqualLoc;
|
|
|
|
ExprResult DefaultArg;
|
2013-12-17 22:12:37 +08:00
|
|
|
if (TryConsumeToken(tok::equal, EqualLoc)) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// C++ [temp.param]p15:
|
|
|
|
// When parsing a default template-argument for a non-type
|
|
|
|
// template-parameter, the first non-nested > is taken as the
|
|
|
|
// end of the template-parameter-list rather than a greater-than
|
|
|
|
// operator.
|
|
|
|
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
2017-04-02 05:30:49 +08:00
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2014-12-03 07:32:20 +08:00
|
|
|
DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
2013-06-09 03:39:00 +08:00
|
|
|
if (DefaultArg.isInvalid())
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the parameter.
|
2018-07-31 03:24:48 +08:00
|
|
|
return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
|
|
|
|
Depth, Position, EqualLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
DefaultArg.get());
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2014-06-06 10:58:59 +08:00
|
|
|
void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
|
|
|
|
SourceLocation CorrectLoc,
|
|
|
|
bool AlreadyHasEllipsis,
|
|
|
|
bool IdentifierHasName) {
|
|
|
|
FixItHint Insertion;
|
|
|
|
if (!AlreadyHasEllipsis)
|
|
|
|
Insertion = FixItHint::CreateInsertion(CorrectLoc, "...");
|
|
|
|
Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration)
|
|
|
|
<< FixItHint::CreateRemoval(EllipsisLoc) << Insertion
|
|
|
|
<< !IdentifierHasName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc,
|
|
|
|
Declarator &D) {
|
|
|
|
assert(EllipsisLoc.isValid());
|
|
|
|
bool AlreadyHasEllipsis = D.getEllipsisLoc().isValid();
|
|
|
|
if (!AlreadyHasEllipsis)
|
|
|
|
D.setEllipsisLoc(EllipsisLoc);
|
|
|
|
DiagnoseMisplacedEllipsis(EllipsisLoc, D.getIdentifierLoc(),
|
|
|
|
AlreadyHasEllipsis, D.hasName());
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parses a '>' at the end of a template list.
|
2013-06-09 03:39:00 +08:00
|
|
|
///
|
|
|
|
/// If this function encounters '>>', '>>>', '>=', or '>>=', it tries
|
|
|
|
/// to determine if these tokens were supposed to be a '>' followed by
|
|
|
|
/// '>', '>>', '>=', or '>='. It emits an appropriate diagnostic if necessary.
|
|
|
|
///
|
|
|
|
/// \param RAngleLoc the location of the consumed '>'.
|
|
|
|
///
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
/// \param ConsumeLastToken if true, the '>' is consumed.
|
|
|
|
///
|
|
|
|
/// \param ObjCGenericList if true, this is the '>' closing an Objective-C
|
|
|
|
/// type parameter or type argument list, rather than a C++ template parameter
|
|
|
|
/// or argument list.
|
2013-08-10 13:54:47 +08:00
|
|
|
///
|
|
|
|
/// \returns true, if current token does not start with '>', false otherwise.
|
2013-06-09 03:39:00 +08:00
|
|
|
bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
bool ConsumeLastToken,
|
|
|
|
bool ObjCGenericList) {
|
2013-06-09 03:39:00 +08:00
|
|
|
// What will be left once we've consumed the '>'.
|
|
|
|
tok::TokenKind RemainingToken;
|
|
|
|
const char *ReplacementStr = "> >";
|
2018-04-30 13:25:48 +08:00
|
|
|
bool MergeWithNextToken = false;
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default:
|
2014-01-01 11:08:43 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected) << tok::greater;
|
2013-06-09 03:39:00 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
case tok::greater:
|
|
|
|
// Determine the location of the '>' token. Only consume this token
|
|
|
|
// if the caller asked us to.
|
|
|
|
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 = "> =";
|
2018-04-30 13:25:48 +08:00
|
|
|
|
|
|
|
// Join two adjacent '=' tokens into one, for cases like:
|
|
|
|
// void (*p)() = f<int>;
|
|
|
|
// return f<int>==p;
|
|
|
|
if (NextToken().is(tok::equal) &&
|
|
|
|
areTokensAdjacent(Tok, NextToken())) {
|
|
|
|
RemainingToken = tok::equalequal;
|
|
|
|
MergeWithNextToken = true;
|
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::greatergreaterequal:
|
|
|
|
RemainingToken = tok::greaterequal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-30 13:25:48 +08:00
|
|
|
// This template-id is terminated by a token that starts with a '>'.
|
|
|
|
// Outside C++11 and Objective-C, this is now error recovery.
|
|
|
|
//
|
|
|
|
// C++11 allows this when the token is '>>', and in CUDA + C++11 mode, we
|
|
|
|
// extend that treatment to also apply to the '>>>' token.
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
//
|
2018-04-30 13:25:48 +08:00
|
|
|
// Objective-C allows this in its type parameter / argument lists.
|
|
|
|
|
|
|
|
SourceLocation TokBeforeGreaterLoc = PrevTokLocation;
|
|
|
|
SourceLocation TokLoc = Tok.getLocation();
|
2013-06-09 03:39:00 +08:00
|
|
|
Token Next = NextToken();
|
2018-04-30 13:25:48 +08:00
|
|
|
|
|
|
|
// Whether splitting the current token after the '>' would undesirably result
|
|
|
|
// in the remaining token pasting with the token after it. This excludes the
|
|
|
|
// MergeWithNextToken cases, which we've already handled.
|
|
|
|
bool PreventMergeWithNextToken =
|
|
|
|
(RemainingToken == tok::greater ||
|
|
|
|
RemainingToken == tok::greatergreater) &&
|
|
|
|
(Next.isOneOf(tok::greater, tok::greatergreater,
|
|
|
|
tok::greatergreatergreater, tok::equal, tok::greaterequal,
|
|
|
|
tok::greatergreaterequal, tok::equalequal)) &&
|
|
|
|
areTokensAdjacent(Tok, Next);
|
|
|
|
|
|
|
|
// Diagnose this situation as appropriate.
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (!ObjCGenericList) {
|
2018-04-30 13:25:48 +08:00
|
|
|
// The source range of the replaced token(s).
|
|
|
|
CharSourceRange ReplacementRange = CharSourceRange::getCharRange(
|
|
|
|
TokLoc, Lexer::AdvanceToTokenCharacter(TokLoc, 2, PP.getSourceManager(),
|
|
|
|
getLangOpts()));
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
|
|
|
// A hint to put a space between the '>>'s. In order to make the hint as
|
|
|
|
// clear as possible, we include the characters either side of the space in
|
|
|
|
// the replacement, rather than just inserting a space at SecondCharLoc.
|
|
|
|
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
|
|
|
ReplacementStr);
|
|
|
|
|
|
|
|
// A hint to put another space after the token, if it would otherwise be
|
|
|
|
// lexed differently.
|
|
|
|
FixItHint Hint2;
|
2018-04-30 13:25:48 +08:00
|
|
|
if (PreventMergeWithNextToken)
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
|
|
|
|
|
|
|
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
|
|
|
if (getLangOpts().CPlusPlus11 &&
|
|
|
|
(Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
|
|
|
|
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
|
|
|
else if (Tok.is(tok::greaterequal))
|
|
|
|
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
2018-04-30 13:25:48 +08:00
|
|
|
Diag(TokLoc, DiagId) << Hint1 << Hint2;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2018-04-30 13:25:48 +08:00
|
|
|
// Find the "length" of the resulting '>' token. This is not always 1, as it
|
|
|
|
// can contain escaped newlines.
|
|
|
|
unsigned GreaterLength = Lexer::getTokenPrefixLength(
|
|
|
|
TokLoc, 1, PP.getSourceManager(), getLangOpts());
|
|
|
|
|
|
|
|
// Annotate the source buffer to indicate that we split the token after the
|
|
|
|
// '>'. This allows us to properly find the end of, and extract the spelling
|
|
|
|
// of, the '>' token later.
|
|
|
|
RAngleLoc = PP.SplitToken(TokLoc, GreaterLength);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// Strip the initial '>' from the token.
|
2018-04-30 13:25:48 +08:00
|
|
|
bool CachingTokens = PP.IsPreviousCachedToken(Tok);
|
|
|
|
|
|
|
|
Token Greater = Tok;
|
|
|
|
Greater.setLocation(RAngleLoc);
|
|
|
|
Greater.setKind(tok::greater);
|
|
|
|
Greater.setLength(GreaterLength);
|
|
|
|
|
|
|
|
unsigned OldLength = Tok.getLength();
|
|
|
|
if (MergeWithNextToken) {
|
2013-06-09 03:39:00 +08:00
|
|
|
ConsumeToken();
|
2018-04-30 13:25:48 +08:00
|
|
|
OldLength += Tok.getLength();
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
2018-04-30 13:25:48 +08:00
|
|
|
|
|
|
|
Tok.setKind(RemainingToken);
|
|
|
|
Tok.setLength(OldLength - GreaterLength);
|
|
|
|
|
|
|
|
// Split the second token if lexing it normally would lex a different token
|
|
|
|
// (eg, the fifth token in 'A<B>>>' should re-lex as '>', not '>>').
|
|
|
|
SourceLocation AfterGreaterLoc = TokLoc.getLocWithOffset(GreaterLength);
|
|
|
|
if (PreventMergeWithNextToken)
|
|
|
|
AfterGreaterLoc = PP.SplitToken(AfterGreaterLoc, Tok.getLength());
|
|
|
|
Tok.setLocation(AfterGreaterLoc);
|
|
|
|
|
|
|
|
// Update the token cache to match what we just did if necessary.
|
|
|
|
if (CachingTokens) {
|
|
|
|
// If the previous cached token is being merged, delete it.
|
|
|
|
if (MergeWithNextToken)
|
|
|
|
PP.ReplacePreviousCachedToken({});
|
|
|
|
|
2016-02-06 03:36:39 +08:00
|
|
|
if (ConsumeLastToken)
|
2018-04-30 13:25:48 +08:00
|
|
|
PP.ReplacePreviousCachedToken({Greater, Tok});
|
2016-02-06 03:36:39 +08:00
|
|
|
else
|
2018-04-30 13:25:48 +08:00
|
|
|
PP.ReplacePreviousCachedToken({Greater});
|
2016-01-31 08:47:51 +08:00
|
|
|
}
|
|
|
|
|
2018-04-30 13:25:48 +08:00
|
|
|
if (ConsumeLastToken) {
|
|
|
|
PrevTokLocation = RAngleLoc;
|
|
|
|
} else {
|
|
|
|
PrevTokLocation = TokBeforeGreaterLoc;
|
2013-06-09 03:39:00 +08:00
|
|
|
PP.EnterToken(Tok);
|
2018-04-30 13:25:48 +08:00
|
|
|
Tok = Greater;
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
2018-04-30 13:25:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parses a template-id that after the template name has
|
2013-06-09 03:39:00 +08:00
|
|
|
/// already been parsed.
|
|
|
|
///
|
|
|
|
/// This routine takes care of parsing the enclosed template argument
|
|
|
|
/// list ('<' template-parameter-list [opt] '>') and placing the
|
|
|
|
/// results into a form that can be transferred to semantic analysis.
|
|
|
|
///
|
|
|
|
/// \param ConsumeLastToken if true, then we will consume the last
|
|
|
|
/// token that forms the template-id. Otherwise, we will leave the
|
|
|
|
/// last token in the stream (e.g., so that it can be replaced with an
|
|
|
|
/// annotation token).
|
|
|
|
bool
|
2017-05-11 05:47:30 +08:00
|
|
|
Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
|
2013-06-09 03:39:00 +08:00
|
|
|
SourceLocation &LAngleLoc,
|
|
|
|
TemplateArgList &TemplateArgs,
|
|
|
|
SourceLocation &RAngleLoc) {
|
|
|
|
assert(Tok.is(tok::less) && "Must have already parsed the template-name");
|
|
|
|
|
|
|
|
// Consume the '<'.
|
|
|
|
LAngleLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the optional template-argument-list.
|
|
|
|
bool Invalid = false;
|
|
|
|
{
|
|
|
|
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
2018-09-22 01:46:28 +08:00
|
|
|
if (!Tok.isOneOf(tok::greater, tok::greatergreater,
|
|
|
|
tok::greatergreatergreater, tok::greaterequal,
|
|
|
|
tok::greatergreaterequal))
|
2013-06-09 03:39:00 +08:00
|
|
|
Invalid = ParseTemplateArgumentList(TemplateArgs);
|
|
|
|
|
|
|
|
if (Invalid) {
|
|
|
|
// Try to find the closing '>'.
|
2013-11-18 16:17:37 +08:00
|
|
|
if (ConsumeLastToken)
|
|
|
|
SkipUntil(tok::greater, StopAtSemi);
|
|
|
|
else
|
|
|
|
SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken,
|
|
|
|
/*ObjCGenericList=*/false);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Replace the tokens that form a simple-template-id with an
|
2013-06-09 03:39:00 +08:00
|
|
|
/// annotation token containing the complete template-id.
|
|
|
|
///
|
|
|
|
/// The first token in the stream must be the name of a template that
|
|
|
|
/// is followed by a '<'. This routine will parse the complete
|
|
|
|
/// simple-template-id and replace the tokens with a single annotation
|
|
|
|
/// token with one of two different kinds: if the template-id names a
|
|
|
|
/// type (and \p AllowTypeAnnotation is true), the annotation token is
|
|
|
|
/// a type annotation that includes the optional nested-name-specifier
|
|
|
|
/// (\p SS). Otherwise, the annotation token is a template-id
|
|
|
|
/// annotation that does not include the optional
|
|
|
|
/// nested-name-specifier.
|
|
|
|
///
|
|
|
|
/// \param Template the declaration of the template named by the first
|
|
|
|
/// token (an identifier), as returned from \c Action::isTemplateName().
|
|
|
|
///
|
|
|
|
/// \param TNK the kind of template that \p Template
|
|
|
|
/// refers to, as returned from \c Action::isTemplateName().
|
|
|
|
///
|
|
|
|
/// \param SS if non-NULL, the nested-name-specifier that precedes
|
|
|
|
/// this template name.
|
|
|
|
///
|
|
|
|
/// \param TemplateKWLoc if valid, specifies that this template-id
|
|
|
|
/// annotation was preceded by the 'template' keyword and gives the
|
|
|
|
/// location of that keyword. If invalid (the default), then this
|
|
|
|
/// template-id was not preceded by a 'template' keyword.
|
|
|
|
///
|
|
|
|
/// \param AllowTypeAnnotation if true (the default), then a
|
|
|
|
/// simple-template-id that refers to a class template, template
|
|
|
|
/// template parameter, or other template that produces a type will be
|
|
|
|
/// replaced with a type annotation token. Otherwise, the
|
|
|
|
/// simple-template-id is always replaced with a template-id
|
|
|
|
/// annotation token.
|
|
|
|
///
|
|
|
|
/// If an unrecoverable parse error occurs and no annotation token can be
|
|
|
|
/// formed, this function returns true.
|
|
|
|
///
|
|
|
|
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");
|
|
|
|
|
|
|
|
// Consume the template-name.
|
|
|
|
SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
|
|
|
|
|
|
|
|
// Parse the enclosed template argument list.
|
|
|
|
SourceLocation LAngleLoc, RAngleLoc;
|
|
|
|
TemplateArgList TemplateArgs;
|
2017-05-11 05:47:30 +08:00
|
|
|
bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
|
2013-06-09 03:39:00 +08:00
|
|
|
TemplateArgs,
|
|
|
|
RAngleLoc);
|
|
|
|
|
|
|
|
if (Invalid) {
|
|
|
|
// If we failed to parse the template ID but skipped ahead to a >, we're not
|
|
|
|
// going to be able to form a token annotation. Eat the '>' if present.
|
2013-12-17 22:12:37 +08:00
|
|
|
TryConsumeToken(tok::greater);
|
2013-06-09 03:39:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
|
|
|
|
|
|
|
|
// Build the annotation token.
|
|
|
|
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
|
2017-01-20 05:00:13 +08:00
|
|
|
TypeResult Type = Actions.ActOnTemplateIdType(
|
|
|
|
SS, TemplateKWLoc, Template, TemplateName.Identifier,
|
|
|
|
TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Type.isInvalid()) {
|
2017-01-20 05:00:13 +08:00
|
|
|
// If we failed to parse the template ID but skipped ahead to a >, we're
|
|
|
|
// not going to be able to form a token annotation. Eat the '>' if
|
|
|
|
// present.
|
2013-12-17 22:12:37 +08:00
|
|
|
TryConsumeToken(tok::greater);
|
2013-06-09 03:39:00 +08:00
|
|
|
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 {
|
|
|
|
// Build a template-id annotation token that can be processed
|
|
|
|
// later.
|
|
|
|
Tok.setKind(tok::annot_template_id);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-05-23 09:07:12 +08:00
|
|
|
IdentifierInfo *TemplateII =
|
2017-12-30 12:15:27 +08:00
|
|
|
TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier
|
2017-05-23 09:07:12 +08:00
|
|
|
? TemplateName.Identifier
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
OverloadedOperatorKind OpKind =
|
2017-12-30 12:15:27 +08:00
|
|
|
TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier
|
2017-05-23 09:07:12 +08:00
|
|
|
? OO_None
|
|
|
|
: TemplateName.OperatorFunctionId.Operator;
|
|
|
|
|
2017-12-19 03:46:56 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
|
|
|
|
SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
|
2017-05-23 09:07:12 +08:00
|
|
|
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
Tok.setAnnotationValue(TemplateId);
|
|
|
|
if (TemplateKWLoc.isValid())
|
|
|
|
Tok.setLocation(TemplateKWLoc);
|
|
|
|
else
|
|
|
|
Tok.setLocation(TemplateNameLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Common fields for the annotation token
|
|
|
|
Tok.setAnnotationEndLoc(RAngleLoc);
|
|
|
|
|
|
|
|
// In case the tokens were cached, have Preprocessor replace them with the
|
|
|
|
// annotation token.
|
|
|
|
PP.AnnotateCachedTokens(Tok);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Replaces a template-id annotation token with a type
|
2013-06-09 03:39:00 +08:00
|
|
|
/// annotation token.
|
|
|
|
///
|
|
|
|
/// If there was a failure when forming the type from the template-id,
|
|
|
|
/// a type annotation token will still be created, but will have a
|
|
|
|
/// NULL type pointer to signify an error.
|
2017-02-02 05:36:38 +08:00
|
|
|
///
|
|
|
|
/// \param IsClassName Is this template-id appearing in a context where we
|
|
|
|
/// know it names a class, such as in an elaborated-type-specifier or
|
|
|
|
/// base-specifier? ('typename' and 'template' are unneeded and disallowed
|
|
|
|
/// in those contexts.)
|
|
|
|
void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
|
2013-06-09 03:39:00 +08:00
|
|
|
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,
|
2017-01-20 05:00:13 +08:00
|
|
|
TemplateId->Name,
|
2013-06-09 03:39:00 +08:00
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
|
|
|
TemplateArgsPtr,
|
2017-02-02 05:36:38 +08:00
|
|
|
TemplateId->RAngleLoc,
|
|
|
|
/*IsCtorOrDtorName*/false,
|
|
|
|
IsClassName);
|
2013-06-09 03:39:00 +08:00
|
|
|
// Create the new "type" annotation token.
|
|
|
|
Tok.setKind(tok::annot_typename);
|
2016-01-16 07:43:34 +08:00
|
|
|
setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
|
2013-06-09 03:39:00 +08:00
|
|
|
if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
|
|
|
|
Tok.setLocation(TemplateId->SS.getBeginLoc());
|
|
|
|
// End location stays the same
|
|
|
|
|
|
|
|
// Replace the template-id annotation token, and possible the scope-specifier
|
|
|
|
// that precedes it, with the typename annotation token.
|
|
|
|
PP.AnnotateCachedTokens(Tok);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether the given token can end a template argument.
|
2013-06-09 03:39:00 +08:00
|
|
|
static bool isEndOfTemplateArgument(Token Tok) {
|
2015-06-18 18:59:26 +08:00
|
|
|
return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a C++ template template argument.
|
2013-06-09 03:39:00 +08:00
|
|
|
ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
|
|
|
|
if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) &&
|
|
|
|
!Tok.is(tok::annot_cxxscope))
|
|
|
|
return ParsedTemplateArgument();
|
|
|
|
|
|
|
|
// C++0x [temp.arg.template]p1:
|
|
|
|
// A template-argument for a template template-parameter shall be the name
|
|
|
|
// of a class template or an alias template, expressed as id-expression.
|
2018-07-31 03:24:48 +08:00
|
|
|
//
|
2013-06-09 03:39:00 +08:00
|
|
|
// We parse an id-expression that refers to a class template or alias
|
|
|
|
// template. The grammar we parse is:
|
|
|
|
//
|
|
|
|
// nested-name-specifier[opt] template[opt] identifier ...[opt]
|
|
|
|
//
|
2018-07-31 03:24:48 +08:00
|
|
|
// followed by a token that terminates a template argument, such as ',',
|
2013-06-09 03:39:00 +08:00
|
|
|
// '>', or (in some cases) '>>'.
|
|
|
|
CXXScopeSpec SS; // nested-name-specifier, if present
|
2016-01-16 07:43:34 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, nullptr,
|
2013-06-09 03:39:00 +08:00
|
|
|
/*EnteringContext=*/false);
|
2016-01-16 07:43:34 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
ParsedTemplateArgument Result;
|
|
|
|
SourceLocation EllipsisLoc;
|
|
|
|
if (SS.isSet() && Tok.is(tok::kw_template)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
// Parse the optional 'template' keyword following the
|
2013-06-09 03:39:00 +08:00
|
|
|
// nested-name-specifier.
|
|
|
|
SourceLocation TemplateKWLoc = ConsumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
// We appear to have a dependent template name.
|
|
|
|
UnqualifiedId Name;
|
|
|
|
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
|
|
|
ConsumeToken(); // the identifier
|
2014-01-05 11:27:11 +08:00
|
|
|
|
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If the next token signals the end of a template argument,
|
|
|
|
// then we have a dependent template name that could be a template
|
|
|
|
// template argument.
|
|
|
|
TemplateTy Template;
|
|
|
|
if (isEndOfTemplateArgument(Tok) &&
|
2016-01-16 07:43:34 +08:00
|
|
|
Actions.ActOnDependentTemplateName(
|
|
|
|
getCurScope(), SS, TemplateKWLoc, Name,
|
|
|
|
/*ObjectType=*/nullptr,
|
|
|
|
/*EnteringContext=*/false, Template))
|
2013-06-09 03:39:00 +08:00
|
|
|
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
|
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::identifier)) {
|
|
|
|
// We may have a (non-dependent) template name.
|
|
|
|
TemplateTy Template;
|
|
|
|
UnqualifiedId Name;
|
|
|
|
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
|
|
|
ConsumeToken(); // the identifier
|
2013-12-17 22:12:37 +08:00
|
|
|
|
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
if (isEndOfTemplateArgument(Tok)) {
|
|
|
|
bool MemberOfUnknownSpecialization;
|
2016-01-16 07:43:34 +08:00
|
|
|
TemplateNameKind TNK = Actions.isTemplateName(
|
|
|
|
getCurScope(), SS,
|
|
|
|
/*hasTemplateKeyword=*/false, Name,
|
|
|
|
/*ObjectType=*/nullptr,
|
|
|
|
/*EnteringContext=*/false, Template, MemberOfUnknownSpecialization);
|
2013-06-09 03:39:00 +08:00
|
|
|
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
|
|
|
|
// We have an id-expression that refers to a class template or
|
2018-07-31 03:24:48 +08:00
|
|
|
// (C++0x) alias template.
|
2013-06-09 03:39:00 +08:00
|
|
|
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If this is a pack expansion, build it as such.
|
|
|
|
if (EllipsisLoc.isValid() && !Result.isInvalid())
|
|
|
|
Result = Actions.ActOnPackExpansion(Result, EllipsisLoc);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
|
|
|
|
///
|
|
|
|
/// template-argument: [C++ 14.2]
|
|
|
|
/// constant-expression
|
|
|
|
/// type-id
|
|
|
|
/// id-expression
|
|
|
|
ParsedTemplateArgument Parser::ParseTemplateArgument() {
|
|
|
|
// C++ [temp.arg]p2:
|
|
|
|
// In a template-argument, an ambiguity between a type-id and an
|
|
|
|
// expression is resolved to a type-id, regardless of the form of
|
|
|
|
// the corresponding template-parameter.
|
|
|
|
//
|
Fix PR25627: constant expressions being odr-used in template arguments.
This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments as constant-expressions by installing the ConstantEvaluated ExpressionEvaluationContext just before attempting the disambiguation - and then making sure that Context carries through into ParseConstantExpression (by refactoring it out into a function that does not create its own EvaluationContext: ParseConstantExpressionInExprEvalContext)
Note, prior to this patch, trunk would correctly disambiguate and identify the expression as an expression - and while it would annotate the token with the expression - it would fail to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done for all Constant Expressions, which would remove it from being considered odr-used). By installing the ConstantExpression Evaluation Context prior to disambiguation, and making sure it carries though, we ensure correct processing of the expression-node.
For e.g:
template<int> struct X { };
void f() {
const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // Should be OK - no capture - but clang errors!
}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627
In summary (and reiteration), the fix is as follows:
- Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying on ParseTemplateArgument getting it right)
- Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, carry the context though into a refactored version of ParseConstantExpression that does not create its own ExpressionEvaluationContext.
See https://reviews.llvm.org/D31588 for additional context regarding some of the more fragile and complicated approaches attempted, and Richard's feedback that eventually shaped the simpler and more robust rendition that is being committed.
Thanks Richard!
llvm-svn: 303492
2017-05-21 03:58:04 +08:00
|
|
|
// Therefore, we initially try to parse a type-id - and isCXXTypeId might look
|
|
|
|
// up and annotate an identifier as an id-expression during disambiguation,
|
|
|
|
// so enter the appropriate context for a constant expression template
|
|
|
|
// argument before trying to disambiguate.
|
|
|
|
|
|
|
|
EnterExpressionEvaluationContext EnterConstantEvaluated(
|
2018-07-13 02:45:41 +08:00
|
|
|
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
|
|
|
|
/*LambdaContextDecl=*/nullptr,
|
|
|
|
/*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument);
|
2013-06-09 03:39:00 +08:00
|
|
|
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
|
2017-12-29 13:41:00 +08:00
|
|
|
TypeResult TypeArg = ParseTypeName(
|
2018-02-28 11:02:23 +08:00
|
|
|
/*Range=*/nullptr, DeclaratorContext::TemplateArgContext);
|
|
|
|
return Actions.ActOnTemplateTypeArgument(TypeArg);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// Try to parse a template template argument.
|
|
|
|
{
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
|
|
|
|
ParsedTemplateArgument TemplateTemplateArgument
|
|
|
|
= ParseTemplateTemplateArgument();
|
|
|
|
if (!TemplateTemplateArgument.isInvalid()) {
|
|
|
|
TPA.Commit();
|
|
|
|
return TemplateTemplateArgument;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// Revert this tentative parse to parse a non-type template argument.
|
|
|
|
TPA.Revert();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
// Parse a non-type template argument.
|
2013-06-09 03:39:00 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
Fix PR25627: constant expressions being odr-used in template arguments.
This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments as constant-expressions by installing the ConstantEvaluated ExpressionEvaluationContext just before attempting the disambiguation - and then making sure that Context carries through into ParseConstantExpression (by refactoring it out into a function that does not create its own EvaluationContext: ParseConstantExpressionInExprEvalContext)
Note, prior to this patch, trunk would correctly disambiguate and identify the expression as an expression - and while it would annotate the token with the expression - it would fail to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done for all Constant Expressions, which would remove it from being considered odr-used). By installing the ConstantExpression Evaluation Context prior to disambiguation, and making sure it carries though, we ensure correct processing of the expression-node.
For e.g:
template<int> struct X { };
void f() {
const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // Should be OK - no capture - but clang errors!
}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627
In summary (and reiteration), the fix is as follows:
- Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying on ParseTemplateArgument getting it right)
- Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, carry the context though into a refactored version of ParseConstantExpression that does not create its own ExpressionEvaluationContext.
See https://reviews.llvm.org/D31588 for additional context regarding some of the more fragile and complicated approaches attempted, and Richard's feedback that eventually shaped the simpler and more robust rendition that is being committed.
Thanks Richard!
llvm-svn: 303492
2017-05-21 03:58:04 +08:00
|
|
|
ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast);
|
2013-06-09 03:39:00 +08:00
|
|
|
if (ExprArg.isInvalid() || !ExprArg.get())
|
|
|
|
return ParsedTemplateArgument();
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
|
2014-05-29 18:55:11 +08:00
|
|
|
ExprArg.get(), Loc);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
/// Determine whether the current tokens can only be parsed as a
|
|
|
|
/// template argument list (starting with the '<') and never as a '<'
|
2013-06-09 03:39:00 +08:00
|
|
|
/// expression.
|
|
|
|
bool Parser::IsTemplateArgumentList(unsigned Skip) {
|
|
|
|
struct AlwaysRevertAction : TentativeParsingAction {
|
|
|
|
AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { }
|
|
|
|
~AlwaysRevertAction() { Revert(); }
|
|
|
|
} Tentative(*this);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
while (Skip) {
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnyToken();
|
2013-06-09 03:39:00 +08:00
|
|
|
--Skip;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// '<'
|
2013-12-17 22:12:37 +08:00
|
|
|
if (!TryConsumeToken(tok::less))
|
2013-06-09 03:39:00 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// An empty template argument list.
|
|
|
|
if (Tok.is(tok::greater))
|
|
|
|
return true;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// See whether we have declaration specifiers, which indicate a type.
|
2014-05-16 09:56:53 +08:00
|
|
|
while (isCXXDeclarationSpecifier() == TPResult::True)
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnyToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If we have a '>' or a ',' then this is a template argument list.
|
2015-06-18 18:59:26 +08:00
|
|
|
return Tok.isOneOf(tok::greater, tok::comma);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTemplateArgumentList - Parse a C++ template-argument-list
|
|
|
|
/// (C++ [temp.names]). Returns true if there was an error.
|
|
|
|
///
|
|
|
|
/// template-argument-list: [C++ 14.2]
|
|
|
|
/// template-argument
|
|
|
|
/// template-argument-list ',' template-argument
|
|
|
|
bool
|
|
|
|
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2014-04-14 00:52:03 +08:00
|
|
|
ColonProtectionRAIIObject ColonProtection(*this, false);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
2013-12-17 22:12:37 +08:00
|
|
|
do {
|
2013-06-09 03:39:00 +08:00
|
|
|
ParsedTemplateArgument Arg = ParseTemplateArgument();
|
2013-12-17 22:12:37 +08:00
|
|
|
SourceLocation EllipsisLoc;
|
|
|
|
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
|
2013-06-09 03:39:00 +08:00
|
|
|
Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
|
|
|
|
|
|
|
|
if (Arg.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
|
2013-06-09 03:39:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save this template argument.
|
|
|
|
TemplateArgs.push_back(Arg);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-06-09 03:39:00 +08:00
|
|
|
// If the next token is a comma, consume it and keep reading
|
|
|
|
// arguments.
|
2013-12-17 22:12:37 +08:00
|
|
|
} while (TryConsumeToken(tok::comma));
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a C++ explicit template instantiation
|
2013-06-09 03:39:00 +08:00
|
|
|
/// (C++ [temp.explicit]).
|
|
|
|
///
|
|
|
|
/// explicit-instantiation:
|
|
|
|
/// 'extern' [opt] 'template' declaration
|
|
|
|
///
|
|
|
|
/// Note that the 'extern' is a GNU extension and C++11 feature.
|
2017-12-29 13:41:00 +08:00
|
|
|
Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context,
|
2013-06-09 03:39:00 +08:00
|
|
|
SourceLocation ExternLoc,
|
|
|
|
SourceLocation TemplateLoc,
|
|
|
|
SourceLocation &DeclEnd,
|
2018-07-13 05:09:05 +08:00
|
|
|
ParsedAttributes &AccessAttrs,
|
2013-06-09 03:39:00 +08:00
|
|
|
AccessSpecifier AS) {
|
|
|
|
// This isn't really required here.
|
|
|
|
ParsingDeclRAIIObject
|
|
|
|
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
|
|
|
|
|
2018-07-13 05:09:05 +08:00
|
|
|
return ParseSingleDeclarationAfterTemplate(
|
|
|
|
Context, ParsedTemplateInfo(ExternLoc, TemplateLoc),
|
|
|
|
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
|
|
|
|
if (TemplateParams)
|
|
|
|
return getTemplateParamsRange(TemplateParams->data(),
|
|
|
|
TemplateParams->size());
|
|
|
|
|
|
|
|
SourceRange R(TemplateLoc);
|
|
|
|
if (ExternLoc.isValid())
|
|
|
|
R.setBegin(ExternLoc);
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:41:30 +08:00
|
|
|
void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) {
|
|
|
|
((Parser *)P)->ParseLateTemplatedFuncDef(LPT);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Late parse a C++ function template in Microsoft mode.
|
2013-08-08 05:41:30 +08:00
|
|
|
void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
|
2013-08-16 16:29:13 +08:00
|
|
|
if (!LPT.D)
|
2013-06-09 03:39:00 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Get the FunctionDecl.
|
2014-01-22 15:29:52 +08:00
|
|
|
FunctionDecl *FunD = LPT.D->getAsFunction();
|
2013-06-09 03:39:00 +08:00
|
|
|
// Track template parameter depth.
|
|
|
|
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
|
|
|
|
|
|
|
|
// To restore the context after late parsing.
|
2015-05-12 07:09:06 +08:00
|
|
|
Sema::ContextRAII GlobalSavedContext(
|
|
|
|
Actions, Actions.Context.getTranslationUnitDecl());
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
SmallVector<ParseScope*, 4> TemplateParamScopeStack;
|
|
|
|
|
2018-11-28 05:20:42 +08:00
|
|
|
// Get the list of DeclContexts to reenter. For inline methods, we only want
|
|
|
|
// to push the DeclContext of the outermost class. This matches the way the
|
|
|
|
// parser normally parses bodies of inline methods when the outermost class is
|
|
|
|
// complete.
|
|
|
|
struct ContainingDC {
|
|
|
|
ContainingDC(DeclContext *DC, bool ShouldPush) : Pair(DC, ShouldPush) {}
|
|
|
|
llvm::PointerIntPair<DeclContext *, 1, bool> Pair;
|
|
|
|
DeclContext *getDC() { return Pair.getPointer(); }
|
|
|
|
bool shouldPushDC() { return Pair.getInt(); }
|
|
|
|
};
|
|
|
|
SmallVector<ContainingDC, 4> DeclContextsToReenter;
|
2014-05-02 10:01:07 +08:00
|
|
|
DeclContext *DD = FunD;
|
2018-11-28 05:20:42 +08:00
|
|
|
DeclContext *NextContaining = Actions.getContainingDC(DD);
|
2013-06-09 03:39:00 +08:00
|
|
|
while (DD && !DD->isTranslationUnit()) {
|
2018-11-28 05:20:42 +08:00
|
|
|
bool ShouldPush = DD == NextContaining;
|
|
|
|
DeclContextsToReenter.push_back({DD, ShouldPush});
|
|
|
|
if (ShouldPush)
|
|
|
|
NextContaining = Actions.getContainingDC(DD);
|
2013-06-09 03:39:00 +08:00
|
|
|
DD = DD->getLexicalParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reenter template scopes from outermost to innermost.
|
2018-11-28 05:20:42 +08:00
|
|
|
for (ContainingDC CDC : reverse(DeclContextsToReenter)) {
|
|
|
|
TemplateParamScopeStack.push_back(
|
|
|
|
new ParseScope(this, Scope::TemplateParamScope));
|
|
|
|
unsigned NumParamLists = Actions.ActOnReenterTemplateScope(
|
|
|
|
getCurScope(), cast<Decl>(CDC.getDC()));
|
2014-05-02 10:01:07 +08:00
|
|
|
CurTemplateDepthTracker.addDepth(NumParamLists);
|
2018-11-28 05:20:42 +08:00
|
|
|
if (CDC.shouldPushDC()) {
|
2014-05-02 10:01:07 +08:00
|
|
|
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
|
2018-11-28 05:20:42 +08:00
|
|
|
Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC());
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:41:30 +08:00
|
|
|
assert(!LPT.Toks.empty() && "Empty body!");
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Append the current token at the end of the new token stream so that it
|
|
|
|
// doesn't get lost.
|
2013-08-08 05:41:30 +08:00
|
|
|
LPT.Toks.push_back(Tok);
|
2016-02-10 02:52:09 +08:00
|
|
|
PP.EnterTokenStream(LPT.Toks, true);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Consume the previously pushed token.
|
|
|
|
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
|
2015-06-18 18:59:26 +08:00
|
|
|
assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try) &&
|
|
|
|
"Inline method not starting with '{', ':' or 'try'");
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Parse the method body. Function body parsing code is similar enough
|
|
|
|
// to be re-used for method bodies as well.
|
2017-08-10 23:43:06 +08:00
|
|
|
ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
|
|
|
|
Scope::CompoundStmtScope);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
// Recreate the containing function DeclContext.
|
2014-08-16 06:15:00 +08:00
|
|
|
Sema::ContextRAII FunctionSavedContext(Actions,
|
|
|
|
Actions.getContainingDC(FunD));
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
|
|
|
|
|
|
|
|
if (Tok.is(tok::kw_try)) {
|
2013-08-08 05:41:30 +08:00
|
|
|
ParseFunctionTryBlock(LPT.D, FnScope);
|
2013-06-09 03:39:00 +08:00
|
|
|
} else {
|
|
|
|
if (Tok.is(tok::colon))
|
2013-08-08 05:41:30 +08:00
|
|
|
ParseConstructorInitializer(LPT.D);
|
2013-06-09 03:39:00 +08:00
|
|
|
else
|
2013-08-08 05:41:30 +08:00
|
|
|
Actions.ActOnDefaultCtorInitializers(LPT.D);
|
2013-06-09 03:39:00 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::l_brace)) {
|
2014-01-22 15:29:52 +08:00
|
|
|
assert((!isa<FunctionTemplateDecl>(LPT.D) ||
|
|
|
|
cast<FunctionTemplateDecl>(LPT.D)
|
|
|
|
->getTemplateParameters()
|
2014-05-02 10:01:07 +08:00
|
|
|
->getDepth() == TemplateParameterDepth - 1) &&
|
2013-06-09 03:39:00 +08:00
|
|
|
"TemplateParameterDepth should be greater than the depth of "
|
|
|
|
"current template being instantiated!");
|
2013-08-08 05:41:30 +08:00
|
|
|
ParseFunctionStatementBody(LPT.D, FnScope);
|
|
|
|
Actions.UnmarkAsLateParsedTemplate(FunD);
|
2013-06-09 03:39:00 +08:00
|
|
|
} else
|
2014-05-21 14:02:52 +08:00
|
|
|
Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
|
2013-06-09 03:39:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exit scopes.
|
|
|
|
FnScope.Exit();
|
2013-07-08 11:55:09 +08:00
|
|
|
SmallVectorImpl<ParseScope *>::reverse_iterator I =
|
2013-06-09 03:39:00 +08:00
|
|
|
TemplateParamScopeStack.rbegin();
|
|
|
|
for (; I != TemplateParamScopeStack.rend(); ++I)
|
|
|
|
delete *I;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Lex a delayed template function for late parsing.
|
2013-06-09 03:39:00 +08:00
|
|
|
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
|
|
|
|
tok::TokenKind kind = Tok.getKind();
|
|
|
|
if (!ConsumeAndStoreFunctionPrologue(Toks)) {
|
|
|
|
// Consume everything up to (and including) the matching right brace.
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're in a function-try-block, we need to store all the catch blocks.
|
|
|
|
if (kind == tok::kw_try) {
|
|
|
|
while (Tok.is(tok::kw_catch)) {
|
|
|
|
ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-27 09:32:04 +08:00
|
|
|
|
|
|
|
/// We've parsed something that could plausibly be intended to be a template
|
|
|
|
/// name (\p LHS) followed by a '<' token, and the following code can't possibly
|
|
|
|
/// be an expression. Determine if this is likely to be a template-id and if so,
|
|
|
|
/// diagnose it.
|
|
|
|
bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
// FIXME: We could look at the token sequence in a lot more detail here.
|
|
|
|
if (SkipUntil(tok::greater, tok::greatergreater, tok::greatergreatergreater,
|
|
|
|
StopAtSemi | StopBeforeMatch)) {
|
|
|
|
TPA.Commit();
|
|
|
|
|
|
|
|
SourceLocation Greater;
|
|
|
|
ParseGreaterThanInTemplateList(Greater, true, false);
|
|
|
|
Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS,
|
|
|
|
Less, Greater);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// There's no matching '>' token, this probably isn't supposed to be
|
|
|
|
// interpreted as a template-id. Parse it as an (ill-formed) comparison.
|
|
|
|
TPA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::checkPotentialAngleBracket(ExprResult &PotentialTemplateName) {
|
|
|
|
assert(Tok.is(tok::less) && "not at a potential angle bracket");
|
|
|
|
|
|
|
|
bool DependentTemplateName = false;
|
|
|
|
if (!Actions.mightBeIntendedToBeTemplateName(PotentialTemplateName,
|
|
|
|
DependentTemplateName))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// OK, this might be a name that the user intended to be parsed as a
|
|
|
|
// template-name, followed by a '<' token. Check for some easy cases.
|
|
|
|
|
|
|
|
// If we have potential_template<>, then it's supposed to be a template-name.
|
|
|
|
if (NextToken().is(tok::greater) ||
|
|
|
|
(getLangOpts().CPlusPlus11 &&
|
|
|
|
NextToken().isOneOf(tok::greatergreater, tok::greatergreatergreater))) {
|
|
|
|
SourceLocation Less = ConsumeToken();
|
|
|
|
SourceLocation Greater;
|
|
|
|
ParseGreaterThanInTemplateList(Greater, true, false);
|
|
|
|
Actions.diagnoseExprIntendedAsTemplateName(
|
|
|
|
getCurScope(), PotentialTemplateName, Less, Greater);
|
|
|
|
// FIXME: Perform error recovery.
|
|
|
|
PotentialTemplateName = ExprError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have 'potential_template<type-id', assume it's supposed to be a
|
|
|
|
// template-name if there's a matching '>' later on.
|
|
|
|
{
|
|
|
|
// FIXME: Avoid the tentative parse when NextToken() can't begin a type.
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
SourceLocation Less = ConsumeToken();
|
|
|
|
if (isTypeIdUnambiguously() &&
|
|
|
|
diagnoseUnknownTemplateId(PotentialTemplateName, Less)) {
|
|
|
|
TPA.Commit();
|
|
|
|
// FIXME: Perform error recovery.
|
|
|
|
PotentialTemplateName = ExprError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TPA.Revert();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, remember that we saw this in case we see a potentially-matching
|
|
|
|
// '>' token later on.
|
|
|
|
AngleBracketTracker::Priority Priority =
|
|
|
|
(DependentTemplateName ? AngleBracketTracker::DependentName
|
|
|
|
: AngleBracketTracker::PotentialTypo) |
|
|
|
|
(Tok.hasLeadingSpace() ? AngleBracketTracker::SpaceBeforeLess
|
|
|
|
: AngleBracketTracker::NoSpaceBeforeLess);
|
|
|
|
AngleBrackets.add(*this, PotentialTemplateName.get(), Tok.getLocation(),
|
|
|
|
Priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Parser::checkPotentialAngleBracketDelimiter(
|
|
|
|
const AngleBracketTracker::Loc &LAngle, const Token &OpToken) {
|
|
|
|
// If a comma in an expression context is followed by a type that can be a
|
|
|
|
// template argument and cannot be an expression, then this is ill-formed,
|
|
|
|
// but might be intended to be part of a template-id.
|
|
|
|
if (OpToken.is(tok::comma) && isTypeIdUnambiguously() &&
|
|
|
|
diagnoseUnknownTemplateId(LAngle.TemplateName, LAngle.LessLoc)) {
|
|
|
|
AngleBrackets.clear(*this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a context that looks like a template-id is followed by '()', then
|
|
|
|
// this is ill-formed, but might be intended to be a template-id
|
|
|
|
// followed by '()'.
|
|
|
|
if (OpToken.is(tok::greater) && Tok.is(tok::l_paren) &&
|
|
|
|
NextToken().is(tok::r_paren)) {
|
|
|
|
Actions.diagnoseExprIntendedAsTemplateName(
|
|
|
|
getCurScope(), LAngle.TemplateName, LAngle.LessLoc,
|
|
|
|
OpToken.getLocation());
|
|
|
|
AngleBrackets.clear(*this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// After a '>' (etc), we're no longer potentially in a construct that's
|
|
|
|
// intended to be treated as a template-id.
|
|
|
|
if (OpToken.is(tok::greater) ||
|
|
|
|
(getLangOpts().CPlusPlus11 &&
|
|
|
|
OpToken.isOneOf(tok::greatergreater, tok::greatergreatergreater)))
|
|
|
|
AngleBrackets.clear(*this);
|
|
|
|
return false;
|
|
|
|
}
|