//===--- ParseTemplate.cpp - Template Parsing -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements parsing of C++ templates.
//
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
/// explicit specialization.
Parser::DeclPtrTy
Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS) {
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less))
return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
DeclEnd);
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
}
/// \brief RAII class that manages the template parameter depth.
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; }
};
}
/// \brief Parse a template declaration or an explicit specialization.
///
/// 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
Parser::DeclPtrTy
Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS) {
assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
"Token does not start a template declaration.");
// Enter template-parameter scope.
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
// 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;
TemplateParameterDepthCounter Depth(TemplateParameterDepth);
do {
// Consume the 'export', if any.
SourceLocation ExportLoc;
if (Tok.is(tok::kw_export)) {
ExportLoc = ConsumeToken();
}
// Consume the 'template', which should be here.
SourceLocation TemplateLoc;
if (Tok.is(tok::kw_template)) {
TemplateLoc = ConsumeToken();
} else {
Diag(Tok.getLocation(), diag::err_expected_template);
return DeclPtrTy();
}
// Parse the '<' template-parameter-list '>'
SourceLocation LAngleLoc, RAngleLoc;
TemplateParameterList TemplateParams;
if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc,
RAngleLoc)) {
// Skip until the semi-colon or a }.
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return DeclPtrTy();
}
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));
// Parse the actual template declaration.
return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(&ParamLists,
isSpecialization,
LastParamListWasEmpty),
DeclEnd,