//===--- ParseExprCXX.cpp - C++ Expression 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 the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "AstGuard.h"
using namespace clang;
/// ParseOptionalCXXScopeSpecifier - Parse global scope or
/// nested-name-specifier if present. Returns true if a nested-name-specifier
/// was parsed from the token stream. Note that this routine will not parse
/// ::new or ::delete, it will just leave them in the token stream.
///
/// '::'[opt] nested-name-specifier
/// '::'
///
/// nested-name-specifier:
/// type-name '::'
/// namespace-name '::'
/// nested-name-specifier identifier '::'
/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
///
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
SS.setScopeRep(Tok.getAnnotationValue());
SS.setRange(Tok.getAnnotationRange());
ConsumeToken();
return true;
}
bool HasScopeSpecifier = false;
if (Tok.is(tok::coloncolon)) {
// ::new and ::delete aren't nested-name-specifiers.
tok::TokenKind NextKind = NextToken().getKind();
if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
return false;
// '::' - Global scope qualifier.
SourceLocation CCLoc = ConsumeToken();
SS.setBeginLoc(CCLoc);
SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
SS.setEndLoc(CCLoc);
HasScopeSpecifier = true;
}
while (true) {
// nested-name-specifier:
// type-name '::'
// namespace-name '::'
// nested-name-specifier identifier '::'
if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
if (!HasScopeSpecifier) {
SS.setBeginLoc(IdLoc);
HasScopeSpecifier = true;
}
if (SS.isInvalid())
continue;
SS.setScopeRep(
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
SS.setEndLoc(CCLoc);
continue;
}
// nested-name-specifier:
// type-name '::'
// nested-name-specifier 'template'[opt] simple-template-id '::'
if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
Tok.is(tok::kw_template)) {
// Parse the optional 'template' keyword, then make sure we have
// 'identifier <' after it.
SourceLocation TemplateKWLoc;
if (Tok.is(tok::kw_template)) {
TemplateKWLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok.getLocation(),
diag::err_id_after_template_in_nested_name_spec)
<< SourceRange(TemplateKWLoc);
break;
}
if (NextToken().isNot(tok::less)) {
Diag(NextToken().getLocation(),
diag::err_less_after_template_name_in_nested_name_spec)
<< Tok.getIdentifierInfo()->getName()
<< SourceRange(TemplateKWLoc, Tok.getLocation());
break;
}
}
else {
// FIXME: If the nested-name-specifier thus far is dependent,
// we need to break out of here, because this '<' is taken as
// an operator and not as part of a simple-template-id.
}
DeclTy *Template = 0;
TemplateNameKind TNK = TNK_Non_template;
// FIXME: If the nested-name-specifier thus far is dependent,
// set TNK = TNK_Dependent_template_name and skip the
// "isTemplateName" check.
TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope, Template, &SS);
if (TNK) {
// We have found a template name, so annotate this this token
// with a template-id annotation. We do not permit the
// template-id to be translated into a type annotation,
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
// token.
AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false);
continue;
}
}
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
// We have
//
// simple-template-id '::'
//
// So we need to check whether the simple-template-id is of the
// right kind (it should name a type), and then convert it into
// a type within the nested-name-specifier.
TemplateIdAnnotation *