#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "AstGuard.h"
using namespace clang;
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)) {
tok::TokenKind NextKind = NextToken().getKind();
if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
return false;
SourceLocation CCLoc = ConsumeToken();
SS.setBeginLoc(CCLoc);
SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
SS.setEndLoc(CCLoc);
HasScopeSpecifier = true;
}
while (true) {
if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
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;
}
if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
Tok.is(tok::kw_template)) {
if (Tok.is(tok::kw_template)) {
SourceLocation 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;
}
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
*Tok.getIdentifierInfo(),
Tok.getLocation(),
SS);
AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
&SS, TemplateKWLoc, false);
continue;
}
TemplateTy Template;
TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope, Template, &SS);
if (TNK) {
AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
continue;
}
}
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(&SS);
SS.clear();
assert(Tok.is(tok::annot_typename) &&
"AnnotateTemplateIdTokenAsType isn't working");
Token TypeToken = Tok;
ConsumeToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
if (!HasScopeSpecifier) {
SS.setBeginLoc(TypeToken.getLocation());
HasScopeSpecifier = true;
}
if (TypeToken.getAnnotationValue())
SS.setScopeRep(
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
TypeToken.getAnnotationValue(),
TypeToken.getAnnotationRange(),
CCLoc));
else
SS.setScopeRep(0);
SS.setEndLoc(CCLoc);
continue;
} else
assert(false && "FIXME: Only type template names supported here");
}
break;
}
return HasScopeSpecifier;
}
Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS);
switch (Tok.getKind()) {
default:
return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
case tok::identifier: {
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation L = ConsumeToken();
return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
&SS, isAddressOfOperand);
}
case tok::kw_operator: {
SourceLocation OperatorLoc = Tok.getLocation();
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
return Actions.ActOnCXXOperatorFunctionIdExpr(
CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
isAddressOfOperand);
if (TypeTy *Type = ParseConversionFunctionId())
return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
Tok.is(tok::l_paren), SS,
isAddressOfOperand);
return ExprError();
}
}
assert(0 && "The switch was supposed to take care everything.");
}
Parser::OwningExprResult Parser::ParseCXXCasts() {
tok::TokenKind Kind = Tok.getKind();
const char *CastName = 0;
switch (Kind) {
default: assert(0 && "Unknown C++ cast!"); abort();
case tok::kw_const_cast: CastName = "const_cast"; break;
case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
case tok::kw_static_cast: CastName = "static_cast"; break;
}
SourceLocation OpLoc = ConsumeToken();
SourceLocation LAngleBracketLoc = Tok.getLocation();
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
TypeResult CastTy = ParseTypeName();
SourceLocation RAngleBracketLoc = Tok.getLocation();
if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << CastName);
OwningExprResult Result(ParseSimpleParenExpression(RParenLoc));
if (!Result.isInvalid() && !CastTy.isInvalid())
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
LAngleBracketLoc, CastTy.get(),
RAngleBracketLoc,
LParenLoc, move(Result), RParenLoc);
return move(Result);
}
Parser::OwningExprResult Parser::ParseCXXTypeid() {
assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
SourceLocation OpLoc = ConsumeToken();
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
"typeid"))
return ExprError();
OwningExprResult Result(Actions);
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (Ty.isInvalid())
return ExprError();
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, true,
Ty.get(), RParenLoc);
} else {
Result = ParseExpression();
if (Result.isInvalid())
SkipUntil(tok::r_paren);
else {
MatchRHSPunctuation(tok::r_paren, LParenLoc);
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, false,
Result.release(), RParenLoc);
}
}
return move(Result);
}
Parser::OwningExprResult Parser::ParseCXXBoolLiteral() {
tok::TokenKind Kind = Tok.getKind();
return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
}
Parser::OwningExprResult Parser::ParseThrowExpression() {
assert(Tok.is(tok::kw_throw) && "Not throw!");
SourceLocation ThrowLoc = ConsumeToken();
switch (Tok.getKind()) { case tok::semi:
case tok::r_paren:
case tok::r_square:
case tok::r_brace:
case tok::colon:
case tok::comma:
return Actions.ActOnCXXThrow(ThrowLoc, ExprArg(Actions));
default:
OwningExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) return move(Expr);
return Actions.ActOnCXXThrow(ThrowLoc, move(Expr));
}
}
Parser::OwningExprResult Parser::ParseCXXThis() {
assert(Tok.is(tok::kw_this) && "Not 'this'!");
SourceLocation ThisLoc = ConsumeToken();
return Actions.ActOnCXXThis(ThisLoc);
}
Parser::OwningExprResult
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
assert(Tok.is(tok::l_paren) && "Expected '('!");
SourceLocation LParenLoc = ConsumeParen();
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(Exprs, CommaLocs)) {
SkipUntil(tok::r_paren);
return ExprError();
}
}
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
LParenLoc, move_arg(Exprs),
&CommaLocs[0], RParenLoc);
}
Parser::OwningExprResult Parser::ParseCXXCondition() {
if (!isCXXConditionDeclaration())
return ParseExpression();
SourceLocation StartLoc = Tok.getLocation();
DeclSpec DS;
ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
ParseDeclarator(DeclaratorInfo);
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi);
return ExprError();
}
DeclaratorInfo.setAsmLabel(AsmLabel.release());
DeclaratorInfo.SetRangeEnd(Loc);
}
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
AttributeList *AttrList = ParseAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
if (Tok.isNot(tok::equal))
return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
SourceLocation EqualLoc = ConsumeToken();
OwningExprResult AssignExpr(ParseAssignmentExpression());
if (AssignExpr.isInvalid())
return ExprError();
return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
DeclaratorInfo,EqualLoc,
move(AssignExpr));
}
void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec;
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
case tok::identifier: case tok::coloncolon: assert(0 && "Annotation token should already be formed!");
default:
assert(0 && "Not a simple-type-specifier token!");
abort();
case tok::annot_typename: {
DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
Tok.getAnnotationValue());
break;
}
case tok::kw_short:
DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
break;
case tok::kw_long:
DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
break;
case tok::kw_signed:
DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
break;
case tok::kw_unsigned:
DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
break;
case tok::kw_void:
DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
break;
case tok::kw_char:
DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
break;
case tok::kw_int:
DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
break;
case tok::kw_float:
DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
break;
case tok::kw_double:
DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
break;
case tok::kw_wchar_t:
DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
break;
case tok::kw_bool:
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
break;
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
DS.Finish(Diags, PP);
return;
}
if (Tok.is(tok::annot_typename))
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
else
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
DS.Finish(Diags, PP);
}
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
DS.SetRangeStart(Tok.getLocation());
const char *PrevSpec = 0;
int isInvalid = 0;
if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) {
Diag(Tok, diag::err_operator_missing_type_specifier);
return true;
}
while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ;
return false;
}
OverloadedOperatorKind
Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
SourceLocation Loc;
OverloadedOperatorKind Op = OO_None;
switch (NextToken().getKind()) {
case tok::kw_new:
ConsumeToken(); Loc = ConsumeToken(); if (Tok.is(tok::l_square)) {
ConsumeBracket(); Loc = Tok.getLocation();
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); Op = OO_Array_New;
} else {
Op = OO_New;
}
if (EndLoc)
*EndLoc = Loc;
return Op;
case tok::kw_delete:
ConsumeToken(); Loc = ConsumeToken(); if (Tok.is(tok::l_square)) {
ConsumeBracket(); Loc = Tok.getLocation();
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); Op = OO_Array_Delete;
} else {
Op = OO_Delete;
}
if (EndLoc)
*EndLoc = Loc;
return Op;
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case tok::Token: Op = OO_##Name; break;
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
#include "clang/Basic/OperatorKinds.def"
case tok::l_paren:
ConsumeToken(); ConsumeParen(); Loc = Tok.getLocation();
ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); if (EndLoc)
*EndLoc = Loc;
return OO_Call;
case tok::l_square:
ConsumeToken(); ConsumeBracket(); Loc = Tok.getLocation();
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); if (EndLoc)
*EndLoc = Loc;
return OO_Subscript;
default:
return OO_None;
}
ConsumeToken(); Loc = ConsumeAnyToken(); if (EndLoc)
*EndLoc = Loc;
return Op;
}
Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
ConsumeToken();
DeclSpec DS;
if (ParseCXXTypeSpecifierSeq(DS))
return 0;
Declarator D(DS, Declarator::TypeNameContext);
ParseDeclaratorInternal(D, 0);
if (EndLoc)
*EndLoc = D.getSourceRange().getEnd();
Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
if (Result.isInvalid())
return 0;
else
return Result.get();
}
Parser::OwningExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
assert(Tok.is(tok::kw_new) && "expected 'new' token");
ConsumeToken();
ExprVector PlacementArgs(Actions);
SourceLocation PlacementLParen, PlacementRParen;
bool ParenTypeId;
DeclSpec DS;
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
if (Tok.is(tok::l_paren)) {
PlacementLParen = ConsumeParen();
if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
SkipUntil(tok::semi, true, true);
return ExprError();
}
PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
if (PlacementRParen.isInvalid()) {
SkipUntil(tok::semi, true, true);
return ExprError();
}
if (PlacementArgs.empty()) {
PlacementLParen = PlacementRParen = SourceLocation();
ParenTypeId = true;
} else {
if (Tok.is(tok::l_paren)) {
SourceLocation LParen = ConsumeParen();
ParseSpecifierQualifierList(DS);
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclarator(DeclaratorInfo);
MatchRHSPunctuation(tok::r_paren, LParen);
ParenTypeId = true;
} else {
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
}
ParenTypeId = false;
}
}
} else {
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
}
ParenTypeId = false;
}
if (DeclaratorInfo.isInvalidType()) {
SkipUntil(tok::semi, true, true);
return ExprError();
}
ExprVector ConstructorArgs(Actions);
SourceLocation ConstructorLParen, ConstructorRParen;
if (Tok.is(tok::l_paren)) {
ConstructorLParen = ConsumeParen();
if (Tok.isNot(tok::r_paren)) {
CommaLocsTy CommaLocs;
if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
SkipUntil(tok::semi, true, true);
return ExprError();
}
}
ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
if (ConstructorRParen.isInvalid()) {
SkipUntil(tok::semi, true, true);
return ExprError();
}
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
move_arg(PlacementArgs), PlacementRParen,
ParenTypeId, DeclaratorInfo, ConstructorLParen,
move_arg(ConstructorArgs), ConstructorRParen);
}
void Parser::ParseDirectNewDeclarator(Declarator &D) {
bool first = true;
while (Tok.is(tok::l_square)) {
SourceLocation LLoc = ConsumeBracket();
OwningExprResult Size(first ? ParseExpression()
: ParseConstantExpression());
if (Size.isInvalid()) {
SkipUntil(tok::r_square);
return;
}
first = false;
SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false,
Size.release(), LLoc),
RLoc);
if (RLoc.isInvalid())
return;
}
}
bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
Declarator &D) {
if (isTypeIdInParens()) {
ParseSpecifierQualifierList(D.getMutableDeclSpec());
D.SetSourceRange(D.getDeclSpec().getSourceRange());
ParseDeclarator(D);
return D.isInvalidType();
}
CommaLocsTy CommaLocs;
return ParseExpressionList(PlacementArgs, CommaLocs);
}
Parser::OwningExprResult
Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
ConsumeToken();
bool ArrayDelete = false;
if (Tok.is(tok::l_square)) {
ArrayDelete = true;
SourceLocation LHS = ConsumeBracket();
SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
if (RHS.isInvalid())
return ExprError();
}
OwningExprResult Operand(ParseCastExpression(false));
if (Operand.isInvalid())
return move(Operand);
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand));
}
static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
{
switch(kind) {
default: assert(false && "Not a known unary type trait.");
case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
case tok::kw___is_abstract: return UTT_IsAbstract;
case tok::kw___is_class: return UTT_IsClass;
case tok::kw___is_empty: return UTT_IsEmpty;
case tok::kw___is_enum: return UTT_IsEnum;
case tok::kw___is_pod: return UTT_IsPOD;
case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
case tok::kw___is_union: return UTT_IsUnion;
}
}
Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
{
UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
SourceLocation LParen = Tok.getLocation();
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
return ExprError();
TypeResult Ty = ParseTypeName();
SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
if (Ty.isInvalid())
return ExprError();
return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
}