//===--- ParseExpr.cpp - 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. Expressions in // C99 basically consist of a bunch of binary operators with unary operators and // other random stuff at the leaves. // // In the C99 grammar, these unary operators bind tightest and are represented // as the 'cast-expression' production. Everything else is either a binary // operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are // handled by ParseCastExpression, the higher level pieces are handled by // ParseBinaryExpression. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" #include "clang/Basic/PrettyStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" using namespace clang; /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// static prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus0x) { switch (Kind) { case tok::greater: // C++ [temp.names]p3: // [...] When parsing a template-argument-list, the first // non-nested > is taken as the ending delimiter rather than a // greater-than operator. [...] if (GreaterThanIsOperator) return prec::Relational; return prec::Unknown; case tok::greatergreater: // C++0x [temp.names]p3: // // [...] Similarly, the first non-nested >> is treated as two // consecutive but distinct > tokens, the first of which is // taken as the end of the template-argument-list and completes // the template-id. [...] 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; } } /// ParseExpression - Simple precedence-based parser for binary/ternary /// operators. /// /// Note: we diverge from the C99 grammar when parsing the assignment-expression /// production. C99 specifies that the LHS of an assignment operator should be /// parsed as a unary-expression, but consistency dictates that it be a /// conditional-expession. In practice, the important thing here is that the /// LHS of an assignment has to be an l-value, which productions between /// unary-expression and conditional-expression don't produce. Because we want /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// /// pm-expression: [C++ 5.5] /// cast-expression /// pm-expression '.*' cast-expression /// pm-expression '->*' cast-expression /// /// multiplicative-expression: [C99 6.5.5] /// Note: in C++, apply pm-expression instead of cast-expression /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression /// multiplicative-expression '%' cast-expression /// /// additive-expression: [C99 6.5.6] /// multiplicative-expression /// additive-expression '+' multiplicative-expression /// additive-expression '-' multiplicative-expression /// /// shift-expression: [C99 6.5.7] /// additive-expression /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// /// relational-expression: [C99 6.5.8] /// shift-expression /// relational-expression '<' shift-expression /// relational-expression '>' shift-expression /// relational-expression '<=' shift-expression /// relational-expression '>=' shift-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression /// equality-expression '==' relational-expression /// equality-expression '!=' relational-expression /// /// AND-expression: [C99 6.5.10] /// equality-expression /// AND-expression '&' equality-expression /// /// exclusive-OR-expression: [C99 6.5.11] /// AND-expression /// exclusive-OR-expression '^' AND-expression /// /// inclusive-OR-expression: [C99 6.5.12] /// exclusive-OR-expression /// inclusive-OR-expression '|' exclusive-OR-expression /// /// logical-AND-expression: [C99 6.5.13] /// inclusive-OR-expression /// logical-AND-expression '&&' inclusive-OR-expression /// /// logical-OR-expression: [C99 6.5.14] /// logical-AND-expression /// logical-OR-expression '||' logical-AND-expression /// /// conditional-expression: [C99 6.5.15] /// logical-OR-expression /// logical-OR-expression '?' expression ':' conditional-expression /// [GNU] logical-OR-expression '?' ':' conditional-expression /// [C++] the third operand is an assignment-expression /// /// assignment-expression: [C99 6.5.16] /// conditional-expression /// unary-expression assignment-operator assignment-expression /// [C++] throw-expression [C++ 15] /// /// assignment-operator: one of /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] /// assignment-expression /// expression ',' assignment-expression /// Parser::OwningExprResult Parser::ParseExpression() { OwningExprResult LHS(ParseAssignmentExpression()); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This /// routine is necessary to disambiguate @try-statement from, /// for example, @encode-expression. /// Parser::OwningExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { OwningExprResult LHS(ParseObjCAtExpression(AtLoc)); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// This routine is called when a leading '__extension__' is seen and /// consumed. This is necessary because the token gets consumed in the /// process of disambiguating between an expression and a declaration. Parser::OwningExprResult Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { OwningExprResult LHS(Actions, true); { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); 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); } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// Parser::OwningExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); ConsumeCodeCompletionToken(); } if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); OwningExprResult LHS(ParseCastExpression(false)); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } /// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression /// where part of an objc message send has already been parsed. In this case /// LBracLoc indicates the location of the '[' of the message send, and either /// ReceiverName or ReceiverExpr is non-null indicating the receiver of the /// message. /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. Parser::OwningExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, SourceLocation SuperLoc, TypeTy *ReceiverType, ExprArg ReceiverExpr) { OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, ReceiverType, 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() { // C++ [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. EnterExpressionEvaluationContext Unevaluated(Actions, Action::Unevaluated); OwningExprResult LHS(ParseCastExpression(false)); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Conditional); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); SourceLocation ColonLoc; while (1) { // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! if (NextTokPrec < MinPrec) return move(LHS); // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); // Special case handling for the ternary operator. OwningExprResult TernaryMiddle(Actions, true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not // 'logical-OR-expression' as we might expect. TernaryMiddle = ParseExpression(); if (TernaryMiddle.isInvalid()) return move(TernaryMiddle); } else { // Special case handling of "X ? Y : Z" where Y is empty: // logical-OR-expression '?' ':' conditional-expression [GNU] TernaryMiddle = 0; Diag(Tok, diag::ext_gnu_conditional_expr); } if (Tok.is(tok::colon)) { // Eat the colon. ColonLoc = ConsumeToken(); } else { // Otherwise, we're missing a ':'. Assume that this was a typo that the // user forgot. If we're not in a macro instantion, we can suggest a // fixit hint. If there were two spaces before the current token, // suggest inserting the colon in between them, otherwise insert ": ". SourceLocation FILoc = Tok.getLocation(); const char *FIText = ": "; if (FILoc.isFileID()) { const SourceManager &SM = PP.getSourceManager(); bool IsInvalid = false; const char *SourcePtr = SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { SourcePtr = SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { FILoc = FILoc.getFileLocWithOffset(-1); FIText = ":"; } } } Diag(Tok, diag::err_expected_colon) << FixItHint::CreateInsertion(FILoc, FIText); Diag(OpToken, diag::note_matching) << "?"; ColonLoc = Tok.getLocation(); } } // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could // be a throw-expression, which is not a valid cast-expression. // Therefore we need some special-casing here. // Also note that the third operand of the conditional operator is // an assignment-expression in C++. OwningExprResult RHS(Actions); if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else RHS = ParseCastExpression(false); if (RHS.isInvalid()) return move(RHS); // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || ThisPrec == prec::Assignment; // Get the precedence of the operator to the right of the RHS. If it binds // more tightly with RHS than we do, evaluate it completely first. if (ThisPrec < NextTokPrec || (ThisPrec == NextTokPrec && isRightAssoc)) { // If this is left-associative, only parse things on the RHS that bind // more tightly than the current operator. If it is left-associative, it // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. RHS = ParseRHSOfBinaryExpression(move(RHS), static_cast(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()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { // If we're using '>>' as an operator within a template // argument list (in C++98), suggest the addition of // parentheses so that the code remains well-formed in C++0x. 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)); } } } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. isAddressOfOperand exists because an /// id-expression that is the operand of address-of gets special treatment /// due to member pointers. /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, TypeTy *TypeOfCast) { bool NotCastExpr; OwningExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. isAddressOfOperand exists because an /// id-expression that is the operand of address-of gets special treatment /// due to member pointers. NotCastExpr is set to true if the token is not the /// start of a cast-expression, and no diagnostic is emitted in this case. /// /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression /// /// unary-expression: [C99 6.5.3] /// postfix-expression /// '++' unary-expression /// '--' unary-expression /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++] new-expression /// [C++] delete-expression /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' /// [GNU] '__extension__' '__real' '__imag' /// /// primary-expression: [C99 6.5.1] /// [C99] identifier /// [C++] id-expression /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] /// [C++0x] 'nullptr' [C++0x 2.14.7] /// '(' expression ')' /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '@selector' '(' objc-selector-arg ')' /// [OBJC] '@protocol' '(' identifier ')' /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1] /// [C++] 'this' [C++ 9.3.2] /// [G++] unary-type-trait '(' type-id ')' /// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] /// [clang] '^' block-literal /// /// constant: [C99 6.4.4] /// integer-constant /// floating-constant /// enumeration-constant -> identifier /// character-constant /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// delete-expression: [C++ 5.3.5] /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU] unary-type-trait: /// '__has_nothrow_assign' [TODO] /// '__has_nothrow_copy' [TODO] /// '__has_nothrow_constructor' [TODO] /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' /// '__has_trivial_destructor' /// '__has_virtual_destructor' [TODO] /// '__is_abstract' [TODO] /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' /// '__is_pod' /// '__is_polymorphic' /// '__is_union' /// /// [GNU] binary-type-trait: /// '__is_base_of' [TODO] /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, TypeTy *TypeOfCast) { OwningExprResult Res(Actions); tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; // This handles all of cast-expression, unary-expression, postfix-expression, // and primary-expression. We handle them together like this for efficiency // and to simplify handling of an expression starting with a '(' token: which // may be one of a parenthesized expression, cast-expression, compound literal // expression, or statement expression. // // If the parsed tokens consist of a primary-expression, the cases below // call ParsePostfixExpressionSuffix to handle the postfix expression // suffixes. Cases that cannot be followed by postfix exprs should // return without invoking ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { // If this expression is limited to being a unary-expression, the parent can // not start a cast expression. ParenParseOption ParenExprType = isUnaryExpression ? CompoundLiteral : CastExpr; TypeTy *CastTy; SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; { // The inside of the parens don't need to be a colon protected scope. ColonProtectionRAIIObject X(*this, false); Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, TypeOfCast, CastTy, RParenLoc); if (Res.isInvalid()) return move(Res); } switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. case CompoundStmt: break; // Nothing else to do. case CompoundLiteral: // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of // postfix-expression exist, parse them now. break; case CastExpr: // We have parsed the cast-expression and no postfix-expr pieces are // following. return move(Res); } // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } // primary-expression case tok::numeric_constant: // constant: integer-constant // constant: floating-constant Res = Actions.ActOnNumericConstant(Tok); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::kw_true: case tok::kw_false: return ParseCXXBoolLiteral(); case tok::kw_nullptr: return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLang().CPlusPlus) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || Next.is(tok::less) || Next.is(tok::l_paren)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } } // Consume the identifier so that we can see if it is followed by a '(' or // '.'. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); // Support 'Class.property' and 'super.property' notation. if (getLang().ObjC1 && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, CurScope) || // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && CurScope->isInObjcMethodScope()))) { SourceLocation DotLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_property_name); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, ILoc, PropertyLoc); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. UnqualifiedId Name; CXXScopeSpec ScopeSpec; Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name, Tok.is(tok::l_paren), false); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } case tok::char_constant: // constant: character-constant Res = Actions.ActOnCharacterConstant(Tok); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: Res = ParseStringLiteralExpression(); if (Res.isInvalid()) return move(Res); // This can be followed by postfix-expr pieces (e.g. "foo"[1]). 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: // unary-expression: '++' unary-expression case tok::minusminus: { // unary-expression: '--' unary-expression SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res)); return move(Res); } case tok::amp: { // unary-expression: '&' cast-expression // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res)); return move(Res); } case tok::star: // unary-expression: '*' cast-expression case tok::plus: // unary-expression: '+' cast-expression case tok::minus: // unary-expression: '-' cast-expression case tok::tilde: // unary-expression: '~' cast-expression case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res)); return move(Res); } case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res)); return move(Res); } case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_alignof: case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' // unary-expression: 'alignof' '(' type-id ')' return ParseSizeofAlignofExpression(); case tok::ampamp: { // unary-expression: '&&' identifier 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(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::kw_typeid: Res = ParseCXXTypeid(); // This can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::kw_this: Res = ParseCXXThis(); // This can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_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::kw___vector: case tok::annot_typename: { if (!getLang().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); } if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' if (TryAnnotateTypeOrScopeToken()) return ExprError(); } // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // 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); // This can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. // (We can end up in this situation after tentative parsing.) if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::annot_cxxscope)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast(Next.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id that we know refers to a // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); AnnotateTemplateIdTokenAsType(&SS); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); } } // Parse as an id-expression. Res = ParseCXXIdExpression(isAddressOfOperand); return ParsePostfixExpressionSuffix(move(Res)); } case tok::annot_template_id: { // [C++] template-id TemplateIdAnnotation *TemplateId = static_cast(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template) { // We have a template-id that we know refers to a type, // translate it into a type and continue parsing as a cast // expression. AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); } // Fall through to treat the template-id as an id-expression. } case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id Res = ParseCXXIdExpression(isAddressOfOperand); return ParsePostfixExpressionSuffix(move(Res)); case tok::coloncolon: { // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken // annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); if (Tok.is(tok::kw_new)) return ParseCXXNewExpression(true, CCLoc); if (Tok.is(tok::kw_delete)) return ParseCXXDeleteExpression(true, CCLoc); // This is not a type name or scope specifier, it is an invalid expression. Diag(CCLoc, diag::err_expected_expression); return ExprError(); } case tok::kw_new: // [C++] new-expression return ParseCXXNewExpression(false, Tok.getLocation()); case tok::kw_delete: // [C++] delete-expression return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw___is_pod: // [GNU] unary-type-trait case tok::kw___is_class: case tok::kw___is_enum: case tok::kw___is_union: case tok::kw___is_empty: case tok::kw___is_polymorphic: case tok::kw___is_abstract: case tok::kw___is_literal: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: 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::code_completion: Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); ConsumeCodeCompletionToken(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); case tok::l_square: // These can be followed by postfix-expr pieces. if (getLang().ObjC1) return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); // FALL THROUGH. default: NotCastExpr = true; return ExprError(); } // unreachable. abort(); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression /// is parsed, this method parses any suffixes that apply. /// /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier /// postfix-expression '++' /// postfix-expression '--' /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] /// argument-expression /// argument-expression-list ',' assignment-expression /// Parser::OwningExprResult Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; while (1) { switch (Tok.getKind()) { default: // Not a postfix-expression suffix. return move(LHS); case tok::l_square: { // postfix-expression: p-e '[' expression ']' 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(); // Match the ']'. MatchRHSPunctuation(tok::r_square, Loc); break; } case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')' ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; Loc = ConsumeParen(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0); ConsumeCodeCompletionToken(); } if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall, LHS.get())) { SkipUntil(tok::r_paren); return ExprError(); } } // Match the ')'. 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.data(), Tok.getLocation()); } ConsumeParen(); break; } case tok::arrow: case tok::period: { // postfix-expression: p-e '->' template[opt] id-expression // postfix-expression: p-e '.' template[opt] id-expression tok::TokenKind OpKind = Tok.getKind(); SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. CXXScopeSpec SS; Action::TypeTy *ObjectType = 0; bool MayBePseudoDestructor = false; if (getLang().CPlusPlus && !LHS.isInvalid()) { LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS), OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) break; ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, &MayBePseudoDestructor); } if (Tok.is(tok::code_completion)) { // Code completion for a member access expression. Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(), OpLoc, OpKind == tok::arrow); ConsumeCodeCompletionToken(); } if (MayBePseudoDestructor) { LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS, ObjectType); break; } // Either the action has told is that this cannot be a // pseudo-destructor expression (based on the type of base // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it // names a real destructor. UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/false, ObjectType, Name)) return ExprError(); if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind, SS, Name, ObjCImpDecl, Tok.is(tok::l_paren)); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid()) { LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(), Tok.getKind(), move(LHS)); } ConsumeToken(); break; } } } /// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and /// we are at the start of an expression or a parenthesized type-id. /// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression /// (isCastExpr == false) or the type (isCastExpr == true). /// /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// Parser::OwningExprResult Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, bool &isCastExpr, TypeTy *&CastTy, SourceRange &CastRange) { assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) && "Not a typeof/sizeof/alignof expression!"); OwningExprResult Operand(Actions); // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { isCastExpr = false; if (OpTok.is(tok::kw_typeof) && !getLang().CPlusPlus) { Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo(); return ExprError(); } // C++0x [expr.sizeof]p1: // [...] The operand is either an expression, which is an unevaluated // operand (Clause 5) [...] // // The GNU typeof and alignof extensions also behave as unevaluated // operands. EnterExpressionEvaluationContext Unevaluated(Actions, Action::Unevaluated); Operand = ParseCastExpression(true/*isUnaryExpression*/); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound // literal, or starts with a primary-expression that is a parenthesized // expression. ParenParseOption ExprType = CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; // C++0x [expr.sizeof]p1: // [...] The operand is either an expression, which is an unevaluated // operand (Clause 5) [...] // // The GNU typeof and alignof extensions also behave as unevaluated // operands. EnterExpressionEvaluationContext Unevaluated(Actions, Action::Unevaluated); Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, 0/*TypeOfCast*/, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is // a type. if (ExprType == CastExpr) { isCastExpr = true; return ExprEmpty(); } // If this is a parenthesized expression, it is the start of a // unary-expression, but doesn't include any postfix pieces. Parse these // now if present. Operand = ParsePostfixExpressionSuffix(move(Operand)); } // If we get here, the operand to the typeof/sizeof/alignof was an expresion. isCastExpr = false; return move(Operand); } /// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' 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(); bool isCastExpr; TypeTy *CastTy; SourceRange CastRange; OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, isCastExpr, CastTy, CastRange); if (isCastExpr) return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), OpTok.is(tok::kw_sizeof), /*isType=*/true, CastTy, CastRange); // If we get here, the operand to the sizeof/alignof was an expresion. if (!Operand.isInvalid()) Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), OpTok.is(tok::kw_sizeof), /*isType=*/false, Operand.release(), CastRange); return move(Operand); } /// ParseBuiltinPrimaryExpression /// /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { OwningExprResult Res(Actions); const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); tok::TokenKind T = Tok.getKind(); SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. // All of these start with an open paren. if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after_id) << BuiltinII); SourceLocation LParenLoc = ConsumeParen(); // TODO: Build AST. 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(); // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return ExprError(); } // Keep track of the various subcomponents we see. llvm::SmallVector Comps; Comps.push_back(Action::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); // FIXME: This loop leaks the index expressions on error. while (1) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier 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)) { // offsetof-member-designator: offsetof-member-design '[' expression ']' 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.isNot(tok::r_paren)) { MatchRHSPunctuation(tok::r_paren, LParenLoc); Res = ExprError(); } else if (Ty.isInvalid()) { Res = ExprError(); } else { Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc, Ty.get(), &Comps[0], Comps.size(), ConsumeParen()); } break; } } 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; } // These can be followed by postfix-expr pieces because they are // primary-expressions. return ParsePostfixExpressionSuffix(move(Res)); } /// ParseParenExpression - This parses the unit that starts with a '(' token, /// based on what is allowed by ExprType. The actual thing parsed is returned /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, /// not the parsed cast-expression. /// /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// Parser::OwningExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, TypeTy *TypeOfCast, 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); bool isAmbiguousTypeId; CastTy = 0; if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); OwningStmtResult Stmt(ParseCompoundStatement(0, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation()); } else if (ExprType >= CompoundLiteral && isTypeIdInParens(isAmbiguousTypeId)) { // Otherwise, this is a compound literal expression or cast expression. // In C++, if the type-id is ambiguous we disambiguate based on context. // If stopIfCastExpr is true the context is a typeof/sizeof/alignof // in which case we should treat it as type-id. // if stopIfCastExpr is false, we need to determine the context past the // parens, so we defer to ParseCXXAmbiguousParenExpression for that. if (isAmbiguousTypeId && !stopIfCastExpr) return ParseCXXAmbiguousParenExpression(ExprType, CastTy, OpenLoc, RParenLoc); TypeResult Ty = ParseTypeName(); // Match the ')'. if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else MatchRHSPunctuation(tok::r_paren, OpenLoc); if (Tok.is(tok::l_brace)) { ExprType = CompoundLiteral; return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); } if (ExprType == CastExpr) { // We parsed '(' type-name ')' and the thing after it wasn't a '{'. if (Ty.isInvalid()) return ExprError(); CastTy = Ty.get(); // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. if (stopIfCastExpr) return OwningExprResult(Actions); // Reject the cast of super idiom in ObjC. if (Tok.is(tok::identifier) && getLang().ObjC1 && Tok.getIdentifierInfo() == Ident_super && CurScope->isInObjcMethodScope() && GetLookAheadToken(1).isNot(tok::period)) { Diag(Tok.getLocation(), diag::err_illegal_super_cast) << SourceRange(OpenLoc, RParenLoc); return ExprError(); } // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. Result = ParseCastExpression(false, false, CastTy); if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc, move(Result)); return move(Result); } Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); } else if (TypeOfCast) { // Parse the expression-list. ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), move_arg(ArgExprs), TypeOfCast); } } else { Result = ParseExpression(); ExprType = SimpleExpr; if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), move(Result)); } // Match the ')'. 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); } /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name /// and we are at the left brace. /// /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// Parser::OwningExprResult Parser::ParseCompoundLiteralExpression(TypeTy *Ty, SourceLocation LParenLoc, SourceLocation RParenLoc) { assert(Tok.is(tok::l_brace) && "Not a compound literal!"); if (!getLang().C99) // Compound literals don't exist in C90. Diag(LParenLoc, diag::ext_c99_compound_literal); OwningExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, move(Result)); return move(Result); } /// ParseStringLiteralExpression - This handles the various token types that /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// /// primary-expression: [C99 6.5.1] /// string-literal Parser::OwningExprResult Parser::ParseStringLiteralExpression() { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not // considered to be strings for concatenation purposes. llvm::SmallVector StringToks; do { StringToks.push_back(Tok); ConsumeStringToken(); } while (isTokenStringLiteral()); // Pass the set of string tokens, ready for concatenation, to the actions. return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); } /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// argument-expression-list: /// assignment-expression /// argument-expression-list , assignment-expression /// /// [C++] expression-list: /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, void (Action::*Completer)(Scope *S, void *Data, ExprTy **Args, unsigned NumArgs), void *Data) { while (1) { if (Tok.is(tok::code_completion)) { if (Completer) (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size()); ConsumeCodeCompletionToken(); } OwningExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return true; Exprs.push_back(Expr.release()); if (Tok.isNot(tok::comma)) return false; // Move to the next argument, remember where the comma was. CommaLocs.push_back(ConsumeToken()); } } /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator /// void Parser::ParseBlockId() { // Parse the specifier-qualifier-list piece. DeclSpec DS; ParseSpecifierQualifierList(DS); // Parse the block-declarator. Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); ParseDeclarator(DeclaratorInfo); // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. DeclaratorInfo.AddAttributes(DS.TakeAttributes(), SourceLocation()); if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } // Inform sema that we are starting a block. Actions.ActOnBlockArguments(DeclaratorInfo, CurScope); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// /// block-literal: /// [clang] '^' block-args[opt] compound-statement /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' /// Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); SourceLocation CaretLoc = ConsumeToken(); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, "block literal parsing"); // Enter a scope to hold everything within the block. This includes the // argument decls, decls within the compound expression, etc. This also // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); // Inform sema that we are starting a block. Actions.ActOnBlockStart(CaretLoc, CurScope); // Parse the return type if present. DeclSpec DS; Declarator ParamInfo(DS, Declarator::BlockLiteralContext); // FIXME: Since the return type isn't actually parsed, it can't be used to // fill ParamInfo with an initial valid range, so do it manually. ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); // If this block has arguments, parse them. There is no ambiguity here with // the expression case, because the expression case requires a parameter list. if (Tok.is(tok::l_paren)) { ParseParenDeclarator(ParamInfo); // Parse the pieces after the identifier as if we had "int(...)". // SetIdentifier sets the source range end, but in this case we're past // that location. SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); ParamInfo.SetIdentifier(0, CaretLoc); ParamInfo.SetRangeEnd(Tmp); if (ParamInfo.isInvalidType()) { // If there was an error parsing the arguments, they may have // tried to use ^(x+y) which requires an argument list. Just // skip the whole block literal. Actions.ActOnBlockError(CaretLoc, CurScope); return ExprError(); } if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, CurScope); } else if (!Tok.is(tok::l_brace)) { ParseBlockId(); } else { // Otherwise, pretend we saw (void). ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, SourceLocation(), 0, 0, 0, false, SourceLocation(), false, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), CaretLoc); if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, CurScope); } OwningExprResult Result(Actions, true); if (!Tok.is(tok::l_brace)) { // Saw something like: ^expr 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); }