#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "ExtensionRAIIObject.h"
#include "AstGuard.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
namespace prec {
enum Level {
Unknown = 0, Comma = 1, Assignment = 2, Conditional = 3, LogicalOr = 4, LogicalAnd = 5, InclusiveOr = 6, ExclusiveOr = 7, And = 8, Equality = 9, Relational = 10, Shift = 11, Additive = 12, Multiplicative = 13, PointerToMember = 14 };
}
static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
bool GreaterThanIsOperator,
bool CPlusPlus0x) {
switch (Kind) {
case tok::greater:
if (GreaterThanIsOperator)
return prec::Relational;
return prec::Unknown;
case tok::greatergreater:
if (GreaterThanIsOperator || !CPlusPlus0x)
return prec::Shift;
return prec::Unknown;
default: return prec::Unknown;
case tok::comma: return prec::Comma;
case tok::equal:
case tok::starequal:
case tok::slashequal:
case tok::percentequal:
case tok::plusequal:
case tok::minusequal:
case tok::lesslessequal:
case tok::greatergreaterequal:
case tok::ampequal:
case tok::caretequal:
case tok::pipeequal: return prec::Assignment;
case tok::question: return prec::Conditional;
case tok::pipepipe: return prec::LogicalOr;
case tok::ampamp: return prec::LogicalAnd;
case tok::pipe: return prec::InclusiveOr;
case tok::caret: return prec::ExclusiveOr;
case tok::amp: return prec::And;
case tok::exclaimequal:
case tok::equalequal: return prec::Equality;
case tok::lessequal:
case tok::less:
case tok::greaterequal: return prec::Relational;
case tok::lessless: return prec::Shift;
case tok::plus:
case tok::minus: return prec::Additive;
case tok::percent:
case tok::slash:
case tok::star: return prec::Multiplicative;
case tok::periodstar:
case tok::arrowstar: return prec::PointerToMember;
}
}
Parser::OwningExprResult Parser::ParseExpression() {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
OwningExprResult LHS(ParseCastExpression(false));
if (LHS.isInvalid()) return move(LHS);
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
}
Parser::OwningExprResult
Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
OwningExprResult LHS(ParseObjCAtExpression(AtLoc));
if (LHS.isInvalid()) return move(LHS);
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
}
Parser::OwningExprResult
Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
OwningExprResult LHS(ParseCastExpression(false));
if (LHS.isInvalid()) return move(LHS);
LHS = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__,
move(LHS));
if (LHS.isInvalid()) return move(LHS);
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
}
Parser::OwningExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
OwningExprResult LHS(ParseCastExpression(false));
if (LHS.isInvalid()) return move(LHS);
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
}
Parser::OwningExprResult
Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
SourceLocation NameLoc,
IdentifierInfo *ReceiverName,
ExprArg ReceiverExpr) {
OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc,
ReceiverName,
move(ReceiverExpr)));
if (R.isInvalid()) return move(R);
R = ParsePostfixExpressionSuffix(move(R));
if (R.isInvalid()) return move(R);
return ParseRHSOfBinaryExpression(move(R), prec::Assignment);
}
Parser::OwningExprResult Parser::ParseConstantExpression() {
OwningExprResult LHS(ParseCastExpression(false));
if (LHS.isInvalid()) return move(LHS);
return ParseRHSOfBinaryExpression(move(LHS), prec::Conditional);
}
Parser::OwningExprResult
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
GreaterThanIsOperator,
getLang().CPlusPlus0x);
SourceLocation ColonLoc;
while (1) {
if (NextTokPrec < MinPrec)
return move(LHS);
Token OpToken = Tok;
ConsumeToken();
OwningExprResult TernaryMiddle(Actions, true);
if (NextTokPrec == prec::Conditional) {
if (Tok.isNot(tok::colon)) {
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid())
return move(TernaryMiddle);
} else {
TernaryMiddle = 0;
Diag(Tok, diag::ext_gnu_conditional_expr);
}
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon);
Diag(OpToken, diag::note_matching) << "?";
return ExprError();
}
ColonLoc = ConsumeToken();
}
OwningExprResult RHS(Actions);
if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional)
RHS = ParseAssignmentExpression();
else
RHS = ParseCastExpression(false);
if (RHS.isInvalid())
return move(RHS);
unsigned ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLang().CPlusPlus0x);
bool isRightAssoc = ThisPrec == prec::Conditional ||
ThisPrec == prec::Assignment;
if (ThisPrec < NextTokPrec ||
(ThisPrec == NextTokPrec && isRightAssoc)) {
RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
if (RHS.isInvalid())
return move(RHS);
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLang().CPlusPlus0x);
}
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
if (!LHS.isInvalid()) {
if (TernaryMiddle.isInvalid()) {
if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
SuggestParentheses(OpToken.getLocation(),
diag::warn_cxx0x_right_shift_in_template_arg,
SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
Actions.getExprRange(RHS.get()).getEnd()));
LHS = Actions.ActOnBinOp(CurScope, OpToken.getLocation(),
OpToken.getKind(), move(LHS), move(RHS));
} else
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
move(LHS), move(TernaryMiddle),
move(RHS));
}
}
}
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand) {
OwningExprResult Res(Actions);
tok::TokenKind SavedKind = Tok.getKind();
switch (SavedKind) {
case tok::l_paren: {
ParenParseOption ParenExprType =
isUnaryExpression ? CompoundLiteral : CastExpr;
TypeTy *CastTy;
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc);
if (Res.isInvalid()) return move(Res);
switch (ParenExprType) {
case SimpleExpr: break; case CompoundStmt: break; case CompoundLiteral:
break;
case CastExpr:
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc, move(Res));
return move(Res);
}
return ParsePostfixExpressionSuffix(move(Res));
}
case tok::numeric_constant:
Res = Actions.ActOnNumericConstant(Tok);
ConsumeToken();
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw_true:
case tok::kw_false:
return ParseCXXBoolLiteral();
case tok::identifier: { if (getLang().CPlusPlus) {
if (TryAnnotateTypeOrScopeToken())
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
}
if (getLang().ObjC1 &&
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), CurScope) &&
NextToken().is(tok::period)) {
IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo();
SourceLocation IdentLoc = ConsumeToken();
SourceLocation DotLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return ExprError();
}
IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
SourceLocation PropertyLoc = ConsumeToken();
Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName,
IdentLoc, PropertyLoc);
return ParsePostfixExpressionSuffix(move(Res));
}
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation L = ConsumeToken();
Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren));
return ParsePostfixExpressionSuffix(move(Res));
}
case tok::char_constant: Res = Actions.ActOnCharacterConstant(Tok);
ConsumeToken();
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw___func__: case tok::kw___FUNCTION__: case tok::kw___PRETTY_FUNCTION__: Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
ConsumeToken();
return ParsePostfixExpressionSuffix(move(Res));
case tok::string_literal: case tok::wide_string_literal:
Res = ParseStringLiteralExpression();
if (Res.isInvalid()) return move(Res);
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
case tok::kw___builtin_types_compatible_p:
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
break;
case tok::plusplus: case tok::minusminus: { SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
return move(Res);
}
case tok::amp: { SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false, true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
return move(Res);
}
case tok::star: case tok::plus: case tok::minus: case tok::tilde: case tok::exclaim: case tok::kw___real: case tok::kw___imag: { SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
return move(Res);
}
case tok::kw___extension__:{ ExtensionRAIIObject O(Diags); SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
return move(Res);
}
case tok::kw_sizeof: case tok::kw_alignof:
case tok::kw___alignof: return ParseSizeofAlignofExpression();
case tok::ampamp: { SourceLocation AmpAmpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier))
return ExprError(Diag(Tok, diag::err_expected_ident));
Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(),
Tok.getIdentifierInfo());
ConsumeToken();
return move(Res);
}
case tok::kw_const_cast:
case tok::kw_dynamic_cast:
case tok::kw_reinterpret_cast:
case tok::kw_static_cast:
Res = ParseCXXCasts();
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw_typeid:
Res = ParseCXXTypeid();
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw_this:
Res = ParseCXXThis();
return ParsePostfixExpressionSuffix(move(Res));
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
case tok::annot_typename: {
if (!getLang().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
}
DeclSpec DS;
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
Res = ParseCXXTypeConstructExpression(DS);
return ParsePostfixExpressionSuffix(move(Res));
}
case tok::annot_cxxscope: case tok::kw_operator: Res = ParseCXXIdExpression(isAddressOfOperand);
return ParsePostfixExpressionSuffix(move(Res));
case tok::coloncolon: {
if (TryAnnotateTypeOrScopeToken())
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
SourceLocation CCLoc = ConsumeToken();
if (Tok.is(tok::kw_new))
return ParseCXXNewExpression(true, CCLoc);
if (Tok.is(tok::kw_delete))
return ParseCXXDeleteExpression(true, CCLoc);
Diag(CCLoc, diag::err_expected_expression);
return ExprError();
}
case tok::kw_new: return ParseCXXNewExpression(false, Tok.getLocation());
case tok::kw_delete: return ParseCXXDeleteExpression(false, Tok.getLocation());
case tok::kw___is_pod: case tok::kw___is_class:
case tok::kw___is_enum:
case tok::kw___is_union:
case tok::kw___is_polymorphic:
case tok::kw___is_abstract:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_destructor:
return ParseUnaryTypeTrait();
case tok::at: {
SourceLocation AtLoc = ConsumeToken();
return ParseObjCAtExpression(AtLoc);
}
case tok::caret:
return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
case tok::l_square:
if (getLang().ObjC1)
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
default:
Diag(Tok, diag::err_expected_expression);
return ExprError();
}
abort();
}
Parser::OwningExprResult
Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
SourceLocation Loc;
while (1) {
switch (Tok.getKind()) {
default: return move(LHS);
case tok::l_square: { Loc = ConsumeBracket();
OwningExprResult Idx(ParseExpression());
SourceLocation RLoc = Tok.getLocation();
if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
LHS = Actions.ActOnArraySubscriptExpr(CurScope, move(LHS), Loc,
move(Idx), RLoc);
} else
LHS = ExprError();
MatchRHSPunctuation(tok::r_square, Loc);
break;
}
case tok::l_paren: { ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
Loc = ConsumeParen();
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(ArgExprs, CommaLocs)) {
SkipUntil(tok::r_paren);
return ExprError();
}
}
if (Tok.isNot(tok::r_paren)) {
MatchRHSPunctuation(tok::r_paren, Loc);
return ExprError();
}
if (!LHS.isInvalid()) {
assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
LHS = Actions.ActOnCallExpr(CurScope, move(LHS), Loc,
move_arg(ArgExprs), &CommaLocs[0],
Tok.getLocation());
}
ConsumeParen();
break;
}
case tok::arrow: case tok::period: { tok::TokenKind OpKind = Tok.getKind();
SourceLocation OpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return ExprError();
}
if (!LHS.isInvalid()) {
LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
OpKind, Tok.getLocation(),
*Tok.getIdentifierInfo(),
ObjCImpDecl);
}
ConsumeToken();
break;
}
case tok::plusplus: case tok::minusminus: if (!LHS.isInvalid()) {
LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),
Tok.getKind(), move(LHS));
}
ConsumeToken();
break;
}
}
}
Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() {
assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)
|| Tok.is(tok::kw_alignof)) &&
"Not a sizeof/alignof expression!");
Token OpTok = Tok;
ConsumeToken();
OwningExprResult Operand(Actions);
if (Tok.isNot(tok::l_paren)) {
Operand = ParseCastExpression(true);
} else {
ParenParseOption ExprType = CastExpr;
TypeTy *CastTy;
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
Operand = ParseParenExpression(ExprType, CastTy, RParenLoc);
if (ExprType == CastExpr)
return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
OpTok.is(tok::kw_sizeof),
true, CastTy,
SourceRange(LParenLoc, RParenLoc));
Operand = ParsePostfixExpressionSuffix(move(Operand));
}
if (!Operand.isInvalid())
Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
OpTok.is(tok::kw_sizeof),
false,
Operand.release(), SourceRange());
return move(Operand);
}
Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
OwningExprResult Res(Actions);
const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
tok::TokenKind T = Tok.getKind();
SourceLocation StartLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_id)
<< BuiltinII);
SourceLocation LParenLoc = ConsumeParen();
switch (T) {
default: assert(0 && "Not a builtin primary expression!");
case tok::kw___builtin_va_arg: {
OwningExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
TypeResult Ty = ParseTypeName();
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
return ExprError();
}
if (Ty.isInvalid())
Res = ExprError();
else
Res = Actions.ActOnVAArg(StartLoc, move(Expr), Ty.get(), ConsumeParen());
break;
}
case tok::kw___builtin_offsetof: {
SourceLocation TypeLoc = Tok.getLocation();
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::r_paren);
return ExprError();
}
llvm::SmallVector<Action::OffsetOfComponent, 4> Comps;
Comps.push_back(Action::OffsetOfComponent());
Comps.back().isBrackets = false;
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
while (1) {
if (Tok.is(tok::period)) {
Comps.push_back(Action::OffsetOfComponent());
Comps.back().isBrackets = false;
Comps.back().LocStart = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::r_paren);
return ExprError();
}
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
Comps.back().LocEnd = ConsumeToken();
} else if (Tok.is(tok::l_square)) {
Comps.push_back(Action::OffsetOfComponent());
Comps.back().isBrackets = true;
Comps.back().LocStart = ConsumeBracket();
Res = ParseExpression();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
return move(Res);
}
Comps.back().U.E = Res.release();
Comps.back().LocEnd =
MatchRHSPunctuation(tok::r_square, Comps.back().LocStart);
} else if (Tok.is(tok::r_paren)) {
if (Ty.isInvalid())
Res = ExprError();
else
Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc,
Ty.get(), &Comps[0],
Comps.size(), ConsumeParen());
break;
} else {
return ExprError();
}
}
break;
}
case tok::kw___builtin_choose_expr: {
OwningExprResult Cond(ParseAssignmentExpression());
if (Cond.isInvalid()) {
SkipUntil(tok::r_paren);
return move(Cond);
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
OwningExprResult Expr1(ParseAssignmentExpression());
if (Expr1.isInvalid()) {
SkipUntil(tok::r_paren);
return move(Expr1);
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
OwningExprResult Expr2(ParseAssignmentExpression());
if (Expr2.isInvalid()) {
SkipUntil(tok::r_paren);
return move(Expr2);
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
return ExprError();
}
Res = Actions.ActOnChooseExpr(StartLoc, move(Cond), move(Expr1),
move(Expr2), ConsumeParen());
break;
}
case tok::kw___builtin_types_compatible_p:
TypeResult Ty1 = ParseTypeName();
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
TypeResult Ty2 = ParseTypeName();
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
return ExprError();
}
if (Ty1.isInvalid() || Ty2.isInvalid())
Res = ExprError();
else
Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1.get(), Ty2.get(),
ConsumeParen());
break;
}
return ParsePostfixExpressionSuffix(move(Res));
}
Parser::OwningExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType,
TypeTy *&CastTy, SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
SourceLocation OpenLoc = ConsumeParen();
OwningExprResult Result(Actions, true);
CastTy = 0;
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
OwningStmtResult Stmt(ParseCompoundStatement(true));
ExprType = CompoundStmt;
if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
} else if (ExprType >= CompoundLiteral && isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
MatchRHSPunctuation(tok::r_paren, OpenLoc);
if (Tok.is(tok::l_brace)) {
if (!getLang().C99) Diag(OpenLoc, diag::ext_c99_compound_literal);
Result = ParseInitializer();
ExprType = CompoundLiteral;
if (!Result.isInvalid() && !Ty.isInvalid())
return Actions.ActOnCompoundLiteral(OpenLoc, Ty.get(), RParenLoc,
move(Result));
return move(Result);
}
if (ExprType == CastExpr) {
ExprType = CastExpr;
if (Ty.isInvalid())
return ExprError();
CastTy = Ty.get();
return OwningExprResult(Actions);
}
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
} else {
Result = ParseExpression();
ExprType = SimpleExpr;
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), move(Result));
}
if (Result.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else
MatchRHSPunctuation(tok::r_paren, OpenLoc);
return move(Result);
}
Parser::OwningExprResult Parser::ParseStringLiteralExpression() {
assert(isTokenStringLiteral() && "Not a string literal!");
llvm::SmallVector<Token, 4> StringToks;
do {
StringToks.push_back(Tok);
ConsumeStringToken();
} while (isTokenStringLiteral());
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
}
bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) {
while (1) {
OwningExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid())
return true;
Exprs.push_back(Expr.release());
if (Tok.isNot(tok::comma))
return false;
CommaLocs.push_back(ConsumeToken());
}
}
void Parser::ParseBlockId() {
DeclSpec DS;
ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext);
ParseDeclarator(DeclaratorInfo);
DeclaratorInfo.AddAttributes(DS.TakeAttributes(),
SourceLocation());
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
AttributeList *AttrList = ParseAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
Actions.ActOnBlockArguments(DeclaratorInfo, CurScope);
}
Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
assert(Tok.is(tok::caret) && "block literal starts with ^");
SourceLocation CaretLoc = ConsumeToken();
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc,
"block literal parsing");
ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope);
Actions.ActOnBlockStart(CaretLoc, CurScope);
DeclSpec DS;
Declarator ParamInfo(DS, Declarator::BlockLiteralContext);
ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation()));
if (Tok.is(tok::l_paren)) {
ParseParenDeclarator(ParamInfo);
SourceLocation Tmp = ParamInfo.getSourceRange().getEnd();
ParamInfo.SetIdentifier(0, CaretLoc);
ParamInfo.SetRangeEnd(Tmp);
if (ParamInfo.isInvalidType()) {
Actions.ActOnBlockError(CaretLoc, CurScope);
return ExprError();
}
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
AttributeList *AttrList = ParseAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
Actions.ActOnBlockArguments(ParamInfo, CurScope);
} else if (!Tok.is(tok::l_brace)) {
ParseBlockId();
} else {
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
SourceLocation(),
0, 0, 0,
false, false, 0, 0,
CaretLoc, ParamInfo),
CaretLoc);
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
AttributeList *AttrList = ParseAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
Actions.ActOnBlockArguments(ParamInfo, CurScope);
}
OwningExprResult Result(Actions, true);
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_expression);
Actions.ActOnBlockError(CaretLoc, CurScope);
return ExprError();
}
OwningStmtResult Stmt(ParseCompoundStatementBody());
if (!Stmt.isInvalid())
Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), CurScope);
else
Actions.ActOnBlockError(CaretLoc, CurScope);
return move(Result);
}