| //===--- ParseExpr.cpp - Expression Parsing -------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// Provides 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/AST/ASTContext.h" |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/Basic/PrettyStackTrace.h" |
| #include "clang/Parse/RAIIObjectsForParser.h" |
| #include "clang/Sema/DeclSpec.h" |
| #include "clang/Sema/ParsedTemplate.h" |
| #include "clang/Sema/Scope.h" |
| #include "clang/Sema/TypoCorrection.h" |
| #include "llvm/ADT/SmallVector.h" |
| using namespace clang; |
| |
| /// 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. |
| /// |
| /// \verbatim |
| /// 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 |
| /// |
| /// compare-expression: [C++20 expr.spaceship] |
| /// shift-expression |
| /// compare-expression '<=>' shift-expression |
| /// |
| /// relational-expression: [C99 6.5.8] |
| /// compare-expression |
| /// relational-expression '<' compare-expression |
| /// relational-expression '>' compare-expression |
| /// relational-expression '<=' compare-expression |
| /// relational-expression '>=' compare-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 ...[opt] |
| /// expression ',' assignment-expression ...[opt] |
| /// \endverbatim |
| ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { |
| ExprResult LHS(ParseAssignmentExpression(isTypeCast)); |
| return ParseRHSOfBinaryExpression(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. |
| /// |
| ExprResult |
| Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { |
| ExprResult LHS(ParseObjCAtExpression(AtLoc)); |
| return ParseRHSOfBinaryExpression(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. |
| ExprResult |
| Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { |
| ExprResult LHS(true); |
| { |
| // Silence extension warnings in the sub-expression |
| ExtensionRAIIObject O(Diags); |
| |
| LHS = ParseCastExpression(AnyCastExpr); |
| } |
| |
| if (!LHS.isInvalid()) |
| LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, |
| LHS.get()); |
| |
| return ParseRHSOfBinaryExpression(LHS, prec::Comma); |
| } |
| |
| /// Parse an expr that doesn't include (top-level) commas. |
| ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { |
| if (Tok.is(tok::code_completion)) { |
| cutOffParsing(); |
| Actions.CodeCompleteExpression(getCurScope(), |
| PreferredType.get(Tok.getLocation())); |
| return ExprError(); |
| } |
| |
| if (Tok.is(tok::kw_throw)) |
| return ParseThrowExpression(); |
| if (Tok.is(tok::kw_co_yield)) |
| return ParseCoyieldExpression(); |
| |
| ExprResult LHS = ParseCastExpression(AnyCastExpr, |
| /*isAddressOfOperand=*/false, |
| isTypeCast); |
| return ParseRHSOfBinaryExpression(LHS, prec::Assignment); |
| } |
| |
| /// Parse an assignment expression where part of an Objective-C message |
| /// send has already been parsed. |
| /// |
| /// In this case \p LBracLoc indicates the location of the '[' of the message |
| /// send, and either \p ReceiverName or \p 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. |
| ExprResult |
| Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, |
| SourceLocation SuperLoc, |
| ParsedType ReceiverType, |
| Expr *ReceiverExpr) { |
| ExprResult R |
| = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, |
| ReceiverType, ReceiverExpr); |
| R = ParsePostfixExpressionSuffix(R); |
| return ParseRHSOfBinaryExpression(R, prec::Assignment); |
| } |
| |
| ExprResult |
| Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { |
| assert(Actions.ExprEvalContexts.back().Context == |
| Sema::ExpressionEvaluationContext::ConstantEvaluated && |
| "Call this function only if your ExpressionEvaluationContext is " |
| "already ConstantEvaluated"); |
| ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast)); |
| ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); |
| return Actions.ActOnConstantExpression(Res); |
| } |
| |
| ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { |
| // C++03 [basic.def.odr]p2: |
| // An expression is potentially evaluated unless it appears where an |
| // integral constant expression is required (see 5.19) [...]. |
| // C++98 and C++11 have no such rule, but this is only a defect in C++98. |
| EnterExpressionEvaluationContext ConstantEvaluated( |
| Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); |
| return ParseConstantExpressionInExprEvalContext(isTypeCast); |
| } |
| |
| ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { |
| EnterExpressionEvaluationContext ConstantEvaluated( |
| Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); |
| ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); |
| ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); |
| return Actions.ActOnCaseExpr(CaseLoc, Res); |
| } |
| |
| /// Parse a constraint-expression. |
| /// |
| /// \verbatim |
| /// constraint-expression: C++2a[temp.constr.decl]p1 |
| /// logical-or-expression |
| /// \endverbatim |
| ExprResult Parser::ParseConstraintExpression() { |
| EnterExpressionEvaluationContext ConstantEvaluated( |
| Actions, Sema::ExpressionEvaluationContext::Unevaluated); |
| ExprResult LHS(ParseCastExpression(AnyCastExpr)); |
| ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); |
| if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { |
| Actions.CorrectDelayedTyposInExpr(Res); |
| return ExprError(); |
| } |
| return Res; |
| } |
| |
| /// \brief Parse a constraint-logical-and-expression. |
| /// |
| /// \verbatim |
| /// C++2a[temp.constr.decl]p1 |
| /// constraint-logical-and-expression: |
| /// primary-expression |
| /// constraint-logical-and-expression '&&' primary-expression |
| /// |
| /// \endverbatim |
| ExprResult |
| Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { |
| EnterExpressionEvaluationContext ConstantEvaluated( |
| Actions, Sema::ExpressionEvaluationContext::Unevaluated); |
| bool NotPrimaryExpression = false; |
| auto ParsePrimary = [&] () { |
| ExprResult E = ParseCastExpression(PrimaryExprOnly, |
| /*isAddressOfOperand=*/false, |
| /*isTypeCast=*/NotTypeCast, |
| /*isVectorLiteral=*/false, |
| &NotPrimaryExpression); |
| if (E.isInvalid()) |
| return ExprError(); |
| auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) { |
| E = ParsePostfixExpressionSuffix(E); |
| // Use InclusiveOr, the precedence just after '&&' to not parse the |
| // next arguments to the logical and. |
| E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr); |
| if (!E.isInvalid()) |
| Diag(E.get()->getExprLoc(), |
| Note |
| ? diag::note_unparenthesized_non_primary_expr_in_requires_clause |
| : diag::err_unparenthesized_non_primary_expr_in_requires_clause) |
| << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(") |
| << FixItHint::CreateInsertion( |
| PP.getLocForEndOfToken(E.get()->getEndLoc()), ")") |
| << E.get()->getSourceRange(); |
| return E; |
| }; |
| |
| if (NotPrimaryExpression || |
| // Check if the following tokens must be a part of a non-primary |
| // expression |
| getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, |
| /*CPlusPlus11=*/true) > prec::LogicalAnd || |
| // Postfix operators other than '(' (which will be checked for in |
| // CheckConstraintExpression). |
| Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) || |
| (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) { |
| E = RecoverFromNonPrimary(E, /*Note=*/false); |
| if (E.isInvalid()) |
| return ExprError(); |
| NotPrimaryExpression = false; |
| } |
| bool PossibleNonPrimary; |
| bool IsConstraintExpr = |
| Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary, |
| IsTrailingRequiresClause); |
| if (!IsConstraintExpr || PossibleNonPrimary) { |
| // Atomic constraint might be an unparenthesized non-primary expression |
| // (such as a binary operator), in which case we might get here (e.g. in |
| // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore |
| // the rest of the addition expression). Try to parse the rest of it here. |
| if (PossibleNonPrimary) |
| E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr); |
| Actions.CorrectDelayedTyposInExpr(E); |
| return ExprError(); |
| } |
| return E; |
| }; |
| ExprResult LHS = ParsePrimary(); |
| if (LHS.isInvalid()) |
| return ExprError(); |
| while (Tok.is(tok::ampamp)) { |
| SourceLocation LogicalAndLoc = ConsumeToken(); |
| ExprResult RHS = ParsePrimary(); |
| if (RHS.isInvalid()) { |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| return ExprError(); |
| } |
| ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc, |
| tok::ampamp, LHS.get(), RHS.get()); |
| if (!Op.isUsable()) { |
| Actions.CorrectDelayedTyposInExpr(RHS); |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| return ExprError(); |
| } |
| LHS = Op; |
| } |
| return LHS; |
| } |
| |
| /// \brief Parse a constraint-logical-or-expression. |
| /// |
| /// \verbatim |
| /// C++2a[temp.constr.decl]p1 |
| /// constraint-logical-or-expression: |
| /// constraint-logical-and-expression |
| /// constraint-logical-or-expression '||' |
| /// constraint-logical-and-expression |
| /// |
| /// \endverbatim |
| ExprResult |
| Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { |
| ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause)); |
| if (!LHS.isUsable()) |
| return ExprError(); |
| while (Tok.is(tok::pipepipe)) { |
| SourceLocation LogicalOrLoc = ConsumeToken(); |
| ExprResult RHS = |
| ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); |
| if (!RHS.isUsable()) { |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| return ExprError(); |
| } |
| ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc, |
| tok::pipepipe, LHS.get(), RHS.get()); |
| if (!Op.isUsable()) { |
| Actions.CorrectDelayedTyposInExpr(RHS); |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| return ExprError(); |
| } |
| LHS = Op; |
| } |
| return LHS; |
| } |
| |
| bool Parser::isNotExpressionStart() { |
| tok::TokenKind K = Tok.getKind(); |
| if (K == tok::l_brace || K == tok::r_brace || |
| K == tok::kw_for || K == tok::kw_while || |
| K == tok::kw_if || K == tok::kw_else || |
| K == tok::kw_goto || K == tok::kw_try) |
| return true; |
| // If this is a decl-specifier, we can't be at the start of an expression. |
| return isKnownToBeDeclarationSpecifier(); |
| } |
| |
| bool Parser::isFoldOperator(prec::Level Level) const { |
| return Level > prec::Unknown && Level != prec::Conditional && |
| Level != prec::Spaceship; |
| } |
| |
| bool Parser::isFoldOperator(tok::TokenKind Kind) const { |
| return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true)); |
| } |
| |
| /// Parse a binary expression that starts with \p LHS and has a |
| /// precedence of at least \p MinPrec. |
| ExprResult |
| Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { |
| prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), |
| GreaterThanIsOperator, |
| getLangOpts().CPlusPlus11); |
| SourceLocation ColonLoc; |
| |
| auto SavedType = PreferredType; |
| while (1) { |
| // Every iteration may rely on a preferred type for the whole expression. |
| PreferredType = SavedType; |
| // 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 LHS; |
| |
| // Consume the operator, saving the operator token for error reporting. |
| Token OpToken = Tok; |
| ConsumeToken(); |
| |
| if (OpToken.is(tok::caretcaret)) { |
| return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or)); |
| } |
| |
| // If we're potentially in a template-id, we may now be able to determine |
| // whether we're actually in one or not. |
| if (OpToken.isOneOf(tok::comma, tok::greater, tok::greatergreater, |
| tok::greatergreatergreater) && |
| checkPotentialAngleBracketDelimiter(OpToken)) |
| return ExprError(); |
| |
| // Bail out when encountering a comma followed by a token which can't |
| // possibly be the start of an expression. For instance: |
| // int f() { return 1, } |
| // We can't do this before consuming the comma, because |
| // isNotExpressionStart() looks at the token stream. |
| if (OpToken.is(tok::comma) && isNotExpressionStart()) { |
| PP.EnterToken(Tok, /*IsReinject*/true); |
| Tok = OpToken; |
| return LHS; |
| } |
| |
| // If the next token is an ellipsis, then this is a fold-expression. Leave |
| // it alone so we can handle it in the paren expression. |
| if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) { |
| // FIXME: We can't check this via lookahead before we consume the token |
| // because that tickles a lexer bug. |
| PP.EnterToken(Tok, /*IsReinject*/true); |
| Tok = OpToken; |
| return LHS; |
| } |
| |
| // In Objective-C++, alternative operator tokens can be used as keyword args |
| // in message expressions. Unconsume the token so that it can reinterpreted |
| // as an identifier in ParseObjCMessageExpressionBody. i.e., we support: |
| // [foo meth:0 and:0]; |
| // [foo not_eq]; |
| if (getLangOpts().ObjC && getLangOpts().CPlusPlus && |
| Tok.isOneOf(tok::colon, tok::r_square) && |
| OpToken.getIdentifierInfo() != nullptr) { |
| PP.EnterToken(Tok, /*IsReinject*/true); |
| Tok = OpToken; |
| return LHS; |
| } |
| |
| // Special case handling for the ternary operator. |
| ExprResult TernaryMiddle(true); |
| if (NextTokPrec == prec::Conditional) { |
| if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { |
| // Parse a braced-init-list here for error recovery purposes. |
| SourceLocation BraceLoc = Tok.getLocation(); |
| TernaryMiddle = ParseBraceInitializer(); |
| if (!TernaryMiddle.isInvalid()) { |
| Diag(BraceLoc, diag::err_init_list_bin_op) |
| << /*RHS*/ 1 << PP.getSpelling(OpToken) |
| << Actions.getExprRange(TernaryMiddle.get()); |
| TernaryMiddle = ExprError(); |
| } |
| } else 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(); |
| } else { |
| // Special case handling of "X ? Y : Z" where Y is empty: |
| // logical-OR-expression '?' ':' conditional-expression [GNU] |
| TernaryMiddle = nullptr; |
| Diag(Tok, diag::ext_gnu_conditional_expr); |
| } |
| |
| if (TernaryMiddle.isInvalid()) { |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| LHS = ExprError(); |
| TernaryMiddle = nullptr; |
| } |
| |
| if (!TryConsumeToken(tok::colon, ColonLoc)) { |
| // Otherwise, we're missing a ':'. Assume that this was a typo that |
| // the user forgot. If we're not in a macro expansion, 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 = ": "; |
| const SourceManager &SM = PP.getSourceManager(); |
| if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) { |
| assert(FILoc.isFileID()); |
| bool IsInvalid = false; |
| const char *SourcePtr = |
| SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); |
| if (!IsInvalid && *SourcePtr == ' ') { |
| SourcePtr = |
| SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid); |
| if (!IsInvalid && *SourcePtr == ' ') { |
| FILoc = FILoc.getLocWithOffset(-1); |
| FIText = ":"; |
| } |
| } |
| } |
| |
| Diag(Tok, diag::err_expected) |
| << tok::colon << FixItHint::CreateInsertion(FILoc, FIText); |
| Diag(OpToken, diag::note_matching) << tok::question; |
| ColonLoc = Tok.getLocation(); |
| } |
| } |
| |
| PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(), |
| OpToken.getKind()); |
| // 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++, and in C++11, we can have a |
| // braced-init-list on the RHS of an assignment. For better diagnostics, |
| // parse as if we were allowed braced-init-lists everywhere, and check that |
| // they only appear on the RHS of assignments later. |
| ExprResult RHS; |
| bool RHSIsInitList = false; |
| if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { |
| RHS = ParseBraceInitializer(); |
| RHSIsInitList = true; |
| } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) |
| RHS = ParseAssignmentExpression(); |
| else |
| RHS = ParseCastExpression(AnyCastExpr); |
| |
| if (RHS.isInvalid()) { |
| // FIXME: Errors generated by the delayed typo correction should be |
| // printed before errors from parsing the RHS, not after. |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| if (TernaryMiddle.isUsable()) |
| TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); |
| LHS = ExprError(); |
| } |
| |
| // 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, |
| getLangOpts().CPlusPlus11); |
| |
| // 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 (!RHS.isInvalid() && RHSIsInitList) { |
| Diag(Tok, diag::err_init_list_bin_op) |
| << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); |
| RHS = ExprError(); |
| } |
| // 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(RHS, |
| static_cast<prec::Level>(ThisPrec + !isRightAssoc)); |
| RHSIsInitList = false; |
| |
| if (RHS.isInvalid()) { |
| // FIXME: Errors generated by the delayed typo correction should be |
| // printed before errors from ParseRHSOfBinaryExpression, not after. |
| Actions.CorrectDelayedTyposInExpr(LHS); |
| if (TernaryMiddle.isUsable()) |
| TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); |
| LHS = ExprError(); |
| } |
| |
| NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, |
| getLangOpts().CPlusPlus11); |
| } |
| |
| if (!RHS.isInvalid() && RHSIsInitList) { |
| if (ThisPrec == prec::Assignment) { |
| Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) |
| << Actions.getExprRange(RHS.get()); |
| } else if (ColonLoc.isValid()) { |
| Diag(ColonLoc, diag::err_init_list_bin_op) |
| << /*RHS*/1 << ":" |
| << Actions.getExprRange(RHS.get()); |
| LHS = ExprError(); |
| } else { |
| Diag(OpToken, diag::err_init_list_bin_op) |
| << /*RHS*/1 << PP.getSpelling(OpToken) |
| << Actions.getExprRange(RHS.get()); |
| LHS = ExprError(); |
| } |
| } |
| |
| ExprResult OrigLHS = LHS; |
| 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_cxx11_right_shift_in_template_arg, |
| SourceRange(Actions.getExprRange(LHS.get()).getBegin(), |
| Actions.getExprRange(RHS.get()).getEnd())); |
| |
| ExprResult BinOp = |
| Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), |
| OpToken.getKind(), LHS.get(), RHS.get()); |
| if (BinOp.isInvalid()) |
| BinOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(), |
| RHS.get()->getEndLoc(), |
| {LHS.get(), RHS.get()}); |
| |
| LHS = BinOp; |
| } else { |
| ExprResult CondOp = Actions.ActOnConditionalOp( |
| OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(), |
| RHS.get()); |
| if (CondOp.isInvalid()) { |
| std::vector<clang::Expr *> Args; |
| // TernaryMiddle can be null for the GNU conditional expr extension. |
| if (TernaryMiddle.get()) |
| Args = {LHS.get(), TernaryMiddle.get(), RHS.get()}; |
| else |
| Args = {LHS.get(), RHS.get()}; |
| CondOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(), |
| RHS.get()->getEndLoc(), Args); |
| } |
| |
| LHS = CondOp; |
| } |
| // In this case, ActOnBinOp or ActOnConditionalOp performed the |
| // CorrectDelayedTyposInExpr check. |
| if (!getLangOpts().CPlusPlus) |
| continue; |
| } |
| |
| // Ensure potential typos aren't left undiagnosed. |
| if (LHS.isInvalid()) { |
| Actions.CorrectDelayedTyposInExpr(OrigLHS); |
| Actions.CorrectDelayedTyposInExpr(TernaryMiddle); |
| Actions.CorrectDelayedTyposInExpr(RHS); |
| } |
| } |
| } |
| |
| /// Parse a cast-expression, unary-expression or primary-expression, based |
| /// on \p ExprType. |
| /// |
| /// \p isAddressOfOperand exists because an id-expression that is the |
| /// operand of address-of gets special treatment due to member pointers. |
| /// |
| ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, |
| bool isAddressOfOperand, |
| TypeCastState isTypeCast, |
| bool isVectorLiteral, |
| bool *NotPrimaryExpression) { |
| bool NotCastExpr; |
| ExprResult Res = ParseCastExpression(ParseKind, |
| isAddressOfOperand, |
| NotCastExpr, |
| isTypeCast, |
| isVectorLiteral, |
| NotPrimaryExpression); |
| if (NotCastExpr) |
| Diag(Tok, diag::err_expected_expression); |
| return Res; |
| } |
| |
| namespace { |
| class CastExpressionIdValidator final : public CorrectionCandidateCallback { |
| public: |
| CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes) |
| : NextToken(Next), AllowNonTypes(AllowNonTypes) { |
| WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes; |
| } |
| |
| bool ValidateCandidate(const TypoCorrection &candidate) override { |
| NamedDecl *ND = candidate.getCorrectionDecl(); |
| if (!ND) |
| return candidate.isKeyword(); |
| |
| if (isa<TypeDecl>(ND)) |
| return WantTypeSpecifiers; |
| |
| if (!AllowNonTypes || !CorrectionCandidateCallback::ValidateCandidate(candidate)) |
| return false; |
| |
| if (!NextToken.isOneOf(tok::equal, tok::arrow, tok::period)) |
| return true; |
| |
| for (auto *C : candidate) { |
| NamedDecl *ND = C->getUnderlyingDecl(); |
| if (isa<ValueDecl>(ND) && !isa<FunctionDecl>(ND)) |
| return true; |
| } |
| return false; |
| } |
| |
| std::unique_ptr<CorrectionCandidateCallback> clone() override { |
| return std::make_unique<CastExpressionIdValidator>(*this); |
| } |
| |
| private: |
| Token NextToken; |
| bool AllowNonTypes; |
| }; |
| } |
| |
| /// Parse a cast-expression, or, if \pisUnaryExpression is true, parse |
| /// a unary-expression. |
| /// |
| /// \p 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 and no tokens are consumed. |
| /// |
| /// \verbatim |
| /// cast-expression: [C99 6.5.4] |
| /// unary-expression |
| /// '(' type-name ')' cast-expression |
| /// |
| /// unary-expression: [C99 6.5.3] |
| /// postfix-expression |
| /// '++' unary-expression |
| /// '--' unary-expression |
| /// [Coro] 'co_await' cast-expression |
| /// unary-operator cast-expression |
| /// 'sizeof' unary-expression |
| /// 'sizeof' '(' type-name ')' |
| /// [C++11] 'sizeof' '...' '(' identifier ')' |
| /// [GNU] '__alignof' unary-expression |
| /// [GNU] '__alignof' '(' type-name ')' |
| /// [C11] '_Alignof' '(' type-name ')' |
| /// [C++11] 'alignof' '(' type-id ')' |
| /// [GNU] '&&' identifier |
| /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] |
| /// [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++11] 'nullptr' [C++11 2.14.7] |
| /// [C++11] user-defined-literal |
| /// '(' expression ')' |
| /// [C11] generic-selection |
| /// [C++2a] requires-expression |
| /// '__func__' [C99 6.4.2.2] |
| /// [GNU] '__FUNCTION__' |
| /// [MS] '__FUNCDNAME__' |
| /// [MS] 'L__FUNCTION__' |
| /// [MS] '__FUNCSIG__' |
| /// [MS] 'L__FUNCSIG__' |
| /// [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_FILE' '(' ')' |
| /// [GNU] '__builtin_FUNCTION' '(' ')' |
| /// [GNU] '__builtin_LINE' '(' ')' |
| /// [CLANG] '__builtin_COLUMN' '(' ')' |
| /// [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++11] simple-type-specifier braced-init-list [C++11 5.2.3] |
| /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] |
| /// [C++11] typename-specifier braced-init-list [C++11 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] |
| /// [EMBT] array-type-trait '(' type-id ',' integer ')' |
| /// [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/Embarcadero] unary-type-trait: |
| /// '__is_arithmetic' |
| /// '__is_floating_point' |
| /// '__is_integral' |
| /// '__is_lvalue_expr' |
| /// '__is_rvalue_expr' |
| /// '__is_complete_type' |
| /// '__is_void' |
| /// '__is_array' |
| /// '__is_function' |
| /// '__is_reference' |
| /// '__is_lvalue_reference' |
| /// '__is_rvalue_reference' |
| /// '__is_fundamental' |
| /// '__is_object' |
| /// '__is_scalar' |
| /// '__is_compound' |
| /// '__is_pointer' |
| /// '__is_member_object_pointer' |
| /// '__is_member_function_pointer' |
| /// '__is_member_pointer' |
| /// '__is_const' |
| /// '__is_volatile' |
| /// '__is_trivial' |
| /// '__is_standard_layout' |
| /// '__is_signed' |
| /// '__is_unsigned' |
| /// |
| /// [GNU] unary-type-trait: |
| /// '__has_nothrow_assign' |
| /// '__has_nothrow_copy' |
| /// '__has_nothrow_constructor' |
| /// '__has_trivial_assign' [TODO] |
| /// '__has_trivial_copy' [TODO] |
| /// '__has_trivial_constructor' |
| /// '__has_trivial_destructor' |
| /// '__has_virtual_destructor' |
| /// '__is_abstract' [TODO] |
| /// '__is_class' |
| /// '__is_empty' [TODO] |
| /// '__is_enum' |
| /// '__is_final' |
| /// '__is_pod' |
| /// '__is_polymorphic' |
| /// '__is_sealed' [MS] |
| /// '__is_trivial' |
| /// '__is_union' |
| /// '__has_unique_object_representations' |
| /// |
| /// [Clang] unary-type-trait: |
| /// '__is_aggregate' |
| /// '__trivially_copyable' |
| /// |
| /// binary-type-trait: |
| /// [GNU] '__is_base_of' |
| /// [MS] '__is_convertible_to' |
| /// '__is_convertible' |
| /// '__is_same' |
| /// |
| /// [Embarcadero] array-type-trait: |
| /// '__array_rank' |
| /// '__array_extent' |
| /// |
| /// [Embarcadero] expression-trait: |
| /// '__is_lvalue_expr' |
| /// '__is_rvalue_expr' |
| /// \endverbatim |
| /// |
| ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, |
| bool isAddressOfOperand, |
| bool &NotCastExpr, |
| TypeCastState isTypeCast, |
| bool isVectorLiteral, |
| bool *NotPrimaryExpression) { |
| ExprResult Res; |
| tok::TokenKind SavedKind = Tok.getKind(); |
| auto SavedType = PreferredType; |
| NotCastExpr = false; |
| |
| // Are postfix-expression suffix operators permitted after this |
| // cast-expression? If not, and we find some, we'll parse them anyway and |
| // diagnose them. |
| bool AllowSuffix = true; |
| |
| // 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 |
| // break out of the switch; at the end we call ParsePostfixExpressionSuffix |
| // to handle the postfix expression suffixes. Cases that cannot be followed |
| // by postfix exprs should set AllowSuffix to false. |
| switch (SavedKind) { |
| case tok::l_paren: { |
| // If this expression is limited to being a unary-expression, the paren can |
| // not start a cast expression. |
| ParenParseOption ParenExprType; |
| switch (ParseKind) { |
| case CastParseKind::UnaryExprOnly: |
| if (!getLangOpts().CPlusPlus) |
| ParenExprType = CompoundLiteral; |
| LLVM_FALLTHROUGH; |
| case CastParseKind::AnyCastExpr: |
| ParenExprType = ParenParseOption::CastExpr; |
| break; |
| case CastParseKind::PrimaryExprOnly: |
| ParenExprType = FoldExpr; |
| break; |
| } |
| ParsedType CastTy; |
| SourceLocation RParenLoc; |
| Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, |
| isTypeCast == IsTypeCast, CastTy, RParenLoc); |
| |
| // FIXME: What should we do if a vector literal is followed by a |
| // postfix-expression suffix? Usually postfix operators are permitted on |
| // literals. |
| if (isVectorLiteral) |
| return 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 Res; |
| case FoldExpr: |
| // We only parsed a fold-expression. There might be postfix-expr pieces |
| // afterwards; parse them now. |
| break; |
| } |
| |
| break; |
| } |
| |
| // primary-expression |
| case tok::numeric_constant: |
| // constant: integer-constant |
| // constant: floating-constant |
| |
| Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); |
| ConsumeToken(); |
| break; |
| |
| case tok::kw_true: |
| case tok::kw_false: |
| Res = ParseCXXBoolLiteral(); |
| break; |
| |
| case tok::kw___objc_yes: |
| case tok::kw___objc_no: |
| Res = ParseObjCBoolLiteral(); |
| break; |
| |
| case tok::kw_nullptr: |
| Diag(Tok, diag::warn_cxx98_compat_nullptr); |
| Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); |
| break; |
| |
| case tok::annot_primary_expr: |
| case tok::annot_overload_set: |
| Res = getExprAnnotation(Tok); |
| if (!Res.isInvalid() && Tok.getKind() == tok::annot_overload_set) |
| Res = Actions.ActOnNameClassifiedAsOverloadSet(getCurScope(), Res.get()); |
| ConsumeAnnotationToken(); |
| if (!Res.isInvalid() && Tok.is(tok::less)) |
| checkPotentialAngleBracket(Res); |
| break; |
| |
| case tok::annot_non_type: |
| case tok::annot_non_type_dependent: |
| case tok::annot_non_type_undeclared: { |
| CXXScopeSpec SS; |
| Token Replacement; |
| Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); |
| assert(!Res.isUnset() && |
| "should not perform typo correction on annotation token"); |
| break; |
| } |
| |
| case tok::kw___super: |
| case tok::kw_decltype: |
| // Annotate the token and tail recurse. |
| if (TryAnnotateTypeOrScopeToken()) |
| return ExprError(); |
| assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); |
| return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, |
| isVectorLiteral, NotPrimaryExpression); |
| |
| 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 (getLangOpts().CPlusPlus) { |
| // Avoid the unnecessary parse-time lookup in the common case |
| // where the syntax forbids a type. |
| const Token &Next = NextToken(); |
| |
| // If this identifier was reverted from a token ID, and the next token |
| // is a parenthesis, this is likely to be a use of a type trait. Check |
| // those tokens. |
| if (Next.is(tok::l_paren) && |
| Tok.is(tok::identifier) && |
| Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) { |
| IdentifierInfo *II = Tok.getIdentifierInfo(); |
| // Build up the mapping of revertible type traits, for future use. |
| if (RevertibleTypeTraits.empty()) { |
| #define RTT_JOIN(X,Y) X##Y |
| #define REVERTIBLE_TYPE_TRAIT(Name) \ |
| RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \ |
| = RTT_JOIN(tok::kw_,Name) |
| |
| REVERTIBLE_TYPE_TRAIT(__is_abstract); |
| REVERTIBLE_TYPE_TRAIT(__is_aggregate); |
| REVERTIBLE_TYPE_TRAIT(__is_arithmetic); |
| REVERTIBLE_TYPE_TRAIT(__is_array); |
| REVERTIBLE_TYPE_TRAIT(__is_assignable); |
| REVERTIBLE_TYPE_TRAIT(__is_base_of); |
| REVERTIBLE_TYPE_TRAIT(__is_class); |
| REVERTIBLE_TYPE_TRAIT(__is_complete_type); |
| REVERTIBLE_TYPE_TRAIT(__is_compound); |
| REVERTIBLE_TYPE_TRAIT(__is_const); |
| REVERTIBLE_TYPE_TRAIT(__is_constructible); |
| REVERTIBLE_TYPE_TRAIT(__is_convertible); |
| REVERTIBLE_TYPE_TRAIT(__is_convertible_to); |
| REVERTIBLE_TYPE_TRAIT(__is_destructible); |
| REVERTIBLE_TYPE_TRAIT(__is_empty); |
| REVERTIBLE_TYPE_TRAIT(__is_enum); |
| REVERTIBLE_TYPE_TRAIT(__is_floating_point); |
| REVERTIBLE_TYPE_TRAIT(__is_final); |
| REVERTIBLE_TYPE_TRAIT(__is_function); |
| REVERTIBLE_TYPE_TRAIT(__is_fundamental); |
| REVERTIBLE_TYPE_TRAIT(__is_integral); |
| REVERTIBLE_TYPE_TRAIT(__is_interface_class); |
| REVERTIBLE_TYPE_TRAIT(__is_literal); |
| REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr); |
| REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference); |
| REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer); |
| REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer); |
| REVERTIBLE_TYPE_TRAIT(__is_member_pointer); |
| REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable); |
| REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible); |
| REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible); |
| REVERTIBLE_TYPE_TRAIT(__is_object); |
| REVERTIBLE_TYPE_TRAIT(__is_pod); |
| REVERTIBLE_TYPE_TRAIT(__is_pointer); |
| REVERTIBLE_TYPE_TRAIT(__is_polymorphic); |
| REVERTIBLE_TYPE_TRAIT(__is_reference); |
| REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr); |
| REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference); |
| REVERTIBLE_TYPE_TRAIT(__is_same); |
| REVERTIBLE_TYPE_TRAIT(__is_scalar); |
| REVERTIBLE_TYPE_TRAIT(__is_sealed); |
| REVERTIBLE_TYPE_TRAIT(__is_signed); |
| REVERTIBLE_TYPE_TRAIT(__is_standard_layout); |
| REVERTIBLE_TYPE_TRAIT(__is_trivial); |
| REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable); |
| REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible); |
| REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable); |
| REVERTIBLE_TYPE_TRAIT(__is_union); |
| REVERTIBLE_TYPE_TRAIT(__is_unsigned); |
| REVERTIBLE_TYPE_TRAIT(__is_void); |
| REVERTIBLE_TYPE_TRAIT(__is_volatile); |
| #undef REVERTIBLE_TYPE_TRAIT |
| #undef RTT_JOIN |
| } |
| |
| // If we find that this is in fact the name of a type trait, |
| // update the token kind in place and parse again to treat it as |
| // the appropriate kind of type trait. |
| llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known |
| = RevertibleTypeTraits.find(II); |
| if (Known != RevertibleTypeTraits.end()) { |
| Tok.setKind(Known->second); |
| return ParseCastExpression(ParseKind, isAddressOfOperand, |
| NotCastExpr, isTypeCast, |
| isVectorLiteral, NotPrimaryExpression); |
| } |
| } |
| |
| if ((!ColonIsSacred && Next.is(tok::colon)) || |
| Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren, |
| tok::l_brace)) { |
| // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. |
| if (TryAnnotateTypeOrScopeToken()) |
| return ExprError(); |
| if (!Tok.is(tok::identifier)) |
| return ParseCastExpression(ParseKind, isAddressOfOperand, |
| NotCastExpr, isTypeCast, |
| isVectorLiteral, |
| NotPrimaryExpression); |
| } |
| } |
| |
| // 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 (getLangOpts().ObjC && Tok.is(tok::period) && |
| (Actions.getTypeName(II, ILoc, getCurScope()) || |
| // Allow the base to be 'super' if in an objc-method. |
| (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { |
| ConsumeToken(); |
| |
| if (Tok.is(tok::code_completion) && &II != Ident_super) { |
| cutOffParsing(); |
| Actions.CodeCompleteObjCClassPropertyRefExpr( |
| getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); |
| return ExprError(); |
| } |
| // Allow either an identifier or the keyword 'class' (in C++). |
| if (Tok.isNot(tok::identifier) && |
| !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { |
| Diag(Tok, diag::err_expected_property_name); |
| return ExprError(); |
| } |
| IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); |
| SourceLocation PropertyLoc = ConsumeToken(); |
| |
| Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, |
| ILoc, PropertyLoc); |
| break; |
| } |
| |
| // In an Objective-C method, if we have "super" followed by an identifier, |
| // the token sequence is ill-formed. However, if there's a ':' or ']' after |
| // that identifier, this is probably a message send with a missing open |
| // bracket. Treat it as such. |
| if (getLangOpts().ObjC && &II == Ident_super && !InMessageExpression && |
| getCurScope()->isInObjcMethodScope() && |
| ((Tok.is(tok::identifier) && |
| (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || |
| Tok.is(tok::code_completion))) { |
| Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, |
| nullptr); |
| break; |
| } |
| |
| // If we have an Objective-C class name followed by an identifier |
| // and either ':' or ']', this is an Objective-C class message |
| // send that's missing the opening '['. Recovery |
| // appropriately. Also take this path if we're performing code |
| // completion after an Objective-C class name. |
| if (getLangOpts().ObjC && |
| ((Tok.is(tok::identifier) && !InMessageExpression) || |
| Tok.is(tok::code_completion))) { |
| const Token& Next = NextToken(); |
| if (Tok.is(tok::code_completion) || |
| Next.is(tok::colon) || Next.is(tok::r_square)) |
| if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) |
| if (Typ.get()->isObjCObjectOrInterfaceType()) { |
| // Fake up a Declarator to use with ActOnTypeName. |
| DeclSpec DS(AttrFactory); |
| DS.SetRangeStart(ILoc); |
| DS.SetRangeEnd(ILoc); |
| const char *PrevSpec = nullptr; |
| unsigned DiagID; |
| DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ, |
| Actions.getASTContext().getPrintingPolicy()); |
| |
| Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); |
| TypeResult Ty = Actions.ActOnTypeName(getCurScope(), |
| DeclaratorInfo); |
| if (Ty.isInvalid()) |
| break; |
| |
| Res = ParseObjCMessageExpressionBody(SourceLocation(), |
| SourceLocation(), |
| Ty.get(), nullptr); |
| break; |
| } |
| } |
| |
| // Make sure to pass down the right value for isAddressOfOperand. |
| if (isAddressOfOperand && isPostfixExpressionSuffixStart()) |
| isAddressOfOperand = false; |
| |
| // 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; |
| SourceLocation TemplateKWLoc; |
| Token Replacement; |
| CastExpressionIdValidator Validator( |
| /*Next=*/Tok, |
| /*AllowTypes=*/isTypeCast != NotTypeCast, |
| /*AllowNonTypes=*/isTypeCast != IsTypeCast); |
| Validator.IsAddressOfOperand = isAddressOfOperand; |
| if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) { |
| Validator.WantExpressionKeywords = false; |
| Validator.WantRemainingKeywords = false; |
| } else { |
| Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren); |
| } |
| Name.setIdentifier(&II, ILoc); |
| Res = Actions.ActOnIdExpression( |
| getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), |
| isAddressOfOperand, &Validator, |
| /*IsInlineAsmIdentifier=*/false, |
| Tok.is(tok::r_paren) ? nullptr : &Replacement); |
| if (!Res.isInvalid() && Res.isUnset()) { |
| UnconsumeToken(Replacement); |
| return ParseCastExpression(ParseKind, isAddressOfOperand, |
| NotCastExpr, isTypeCast, |
| /*isVectorLiteral=*/false, |
| NotPrimaryExpression); |
| } |
| if (!Res.isInvalid() && Tok.is(tok::less)) |
| checkPotentialAngleBracket(Res); |
| break; |
| } |
| case tok::char_constant: // constant: character-constant |
| case tok::wide_char_constant: |
| case tok::utf8_char_constant: |
| case tok::utf16_char_constant: |
| case tok::utf32_char_constant: |
| Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); |
| ConsumeToken(); |
| break; |
| case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] |
| case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] |
| case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS] |
| case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS] |
| case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] |
| case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] |
| case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] |
| Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); |
| ConsumeToken(); |
| break; |
| case tok::string_literal: // primary-expression: string-literal |
| case tok::wide_string_literal: |
| case tok::utf8_string_literal: |
| case tok::utf16_string_literal: |
| case tok::utf32_string_literal: |
| Res = ParseStringLiteralExpression(true); |
| break; |
| case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] |
| Res = ParseGenericSelectionExpression(); |
| break; |
| case tok::kw___builtin_available: |
| Res = ParseAvailabilityCheckExpr(Tok.getLocation()); |
| break; |
| case tok::kw___builtin_va_arg: |
| case tok::kw___builtin_offsetof: |
| case tok::kw___builtin_choose_expr: |
| case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() |
| case tok::kw___builtin_convertvector: |
| case tok::kw___builtin_COLUMN: |
| case tok::kw___builtin_FILE: |
| case tok::kw___builtin_FUNCTION: |
| case tok::kw___builtin_LINE: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| // This parses the complete suffix; we can return early. |
| return ParseBuiltinPrimaryExpression(); |
| case tok::kw___null: |
| Res = Actions.ActOnGNUNullExpr(ConsumeToken()); |
| break; |
| |
| case tok::plusplus: // unary-expression: '++' unary-expression [C99] |
| case tok::minusminus: { // unary-expression: '--' unary-expression [C99] |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| // C++ [expr.unary] has: |
| // unary-expression: |
| // ++ cast-expression |
| // -- cast-expression |
| Token SavedTok = Tok; |
| ConsumeToken(); |
| |
| PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(), |
| SavedTok.getLocation()); |
| // One special case is implicitly handled here: if the preceding tokens are |
| // an ambiguous cast expression, such as "(T())++", then we recurse to |
| // determine whether the '++' is prefix or postfix. |
| Res = ParseCastExpression(getLangOpts().CPlusPlus ? |
| UnaryExprOnly : AnyCastExpr, |
| /*isAddressOfOperand*/false, NotCastExpr, |
| NotTypeCast); |
| if (NotCastExpr) { |
| // If we return with NotCastExpr = true, we must not consume any tokens, |
| // so put the token back where we found it. |
| assert(Res.isInvalid()); |
| UnconsumeToken(SavedTok); |
| return ExprError(); |
| } |
| if (!Res.isInvalid()) { |
| Expr *Arg = Res.get(); |
| Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), |
| SavedKind, Arg); |
| if (Res.isInvalid()) |
| Res = Actions.CreateRecoveryExpr(SavedTok.getLocation(), |
| Arg->getEndLoc(), Arg); |
| } |
| return Res; |
| } |
| case tok::amp: { // unary-expression: '&' cast-expression |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| // Special treatment because of member pointers |
| SourceLocation SavedLoc = ConsumeToken(); |
| PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); |
| Res = ParseCastExpression(AnyCastExpr, true); |
| if (!Res.isInvalid()) { |
| Expr *Arg = Res.get(); |
| Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg); |
| if (Res.isInvalid()) |
| Res = Actions.CreateRecoveryExpr(Tok.getLocation(), Arg->getEndLoc(), |
| Arg); |
| } |
| return 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] |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| SourceLocation SavedLoc = ConsumeToken(); |
| PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); |
| Res = ParseCastExpression(AnyCastExpr); |
| if (!Res.isInvalid()) { |
| Expr *Arg = Res.get(); |
| Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg); |
| if (Res.isInvalid()) |
| Res = Actions.CreateRecoveryExpr(SavedLoc, Arg->getEndLoc(), Arg); |
| } |
| return Res; |
| } |
| |
| case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| SourceLocation CoawaitLoc = ConsumeToken(); |
| Res = ParseCastExpression(AnyCastExpr); |
| if (!Res.isInvalid()) |
| Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get()); |
| return Res; |
| } |
| |
| case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] |
| // __extension__ silences extension warnings in the subexpression. |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| ExtensionRAIIObject O(Diags); // Use RAII to do this. |
| SourceLocation SavedLoc = ConsumeToken(); |
| Res = ParseCastExpression(AnyCastExpr); |
| if (!Res.isInvalid()) |
| Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); |
| return Res; |
| } |
| case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')' |
| if (!getLangOpts().C11) |
| Diag(Tok, diag::ext_c11_feature) << Tok.getName(); |
| LLVM_FALLTHROUGH; |
| case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')' |
| case tok::kw___alignof: // unary-expression: '__alignof' unary-expression |
| // unary-expression: '__alignof' '(' type-name ')' |
| case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression |
| // unary-expression: 'sizeof' '(' type-name ')' |
| case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression |
| // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' |
| case tok::kw___builtin_omp_required_simd_align: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| AllowSuffix = false; |
| Res = ParseUnaryExprOrTypeTraitExpression(); |
| break; |
| case tok::ampamp: { // unary-expression: '&&' identifier |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| SourceLocation AmpAmpLoc = ConsumeToken(); |
| if (Tok.isNot(tok::identifier)) |
| return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); |
| |
| if (getCurScope()->getFnParent() == nullptr) |
| return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); |
| |
| Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); |
| LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), |
| Tok.getLocation()); |
| Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); |
| ConsumeToken(); |
| AllowSuffix = false; |
| break; |
| } |
| case tok::kw_const_cast: |
| case tok::kw_dynamic_cast: |
| case tok::kw_reinterpret_cast: |
| case tok::kw_static_cast: |
| case tok::kw_addrspace_cast: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXCasts(); |
| break; |
| case tok::kw___builtin_bit_cast: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseBuiltinBitCast(); |
| break; |
| case tok::kw_typeid: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXTypeid(); |
| break; |
| case tok::kw___uuidof: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXUuidof(); |
| break; |
| case tok::kw_this: |
| Res = ParseCXXThis(); |
| break; |
| case tok::kw___builtin_sycl_unique_stable_name: |
| Res = ParseSYCLUniqueStableNameExpression(); |
| break; |
| |
| case tok::annot_typename: |
| if (isStartOfObjCClassMessageMissingOpenBracket()) { |
| TypeResult Type = getTypeAnnotation(Tok); |
| |
| // Fake up a Declarator to use with ActOnTypeName. |
| DeclSpec DS(AttrFactory); |
| DS.SetRangeStart(Tok.getLocation()); |
| DS.SetRangeEnd(Tok.getLastLoc()); |
| |
| const char *PrevSpec = nullptr; |
| unsigned DiagID; |
| DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), |
| PrevSpec, DiagID, Type, |
| Actions.getASTContext().getPrintingPolicy()); |
| |
| Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); |
| TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); |
| if (Ty.isInvalid()) |
| break; |
| |
| ConsumeAnnotationToken(); |
| Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), |
| Ty.get(), nullptr); |
| break; |
| } |
| LLVM_FALLTHROUGH; |
| |
| case tok::annot_decltype: |
| case tok::kw_char: |
| case tok::kw_wchar_t: |
| case tok::kw_char8_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___int64: |
| case tok::kw___int128: |
| case tok::kw__ExtInt: |
| case tok::kw_signed: |
| case tok::kw_unsigned: |
| case tok::kw_half: |
| case tok::kw_float: |
| case tok::kw_double: |
| case tok::kw___bf16: |
| case tok::kw__Float16: |
| case tok::kw___float128: |
| case tok::kw___ibm128: |
| case tok::kw_void: |
| case tok::kw_typename: |
| case tok::kw_typeof: |
| case tok::kw___vector: |
| #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: |
| #include "clang/Basic/OpenCLImageTypes.def" |
| { |
| if (!getLangOpts().CPlusPlus) { |
| Diag(Tok, diag::err_expected_expression); |
| return ExprError(); |
| } |
| |
| // Everything henceforth is a postfix-expression. |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| |
| if (SavedKind == tok::kw_typename) { |
| // postfix-expression: typename-specifier '(' expression-list[opt] ')' |
| // typename-specifier braced-init-list |
| if (TryAnnotateTypeOrScopeToken()) |
| return ExprError(); |
| |
| if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) |
| // We are trying to parse a simple-type-specifier but might not get such |
| // a token after error recovery. |
| return ExprError(); |
| } |
| |
| // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' |
| // simple-type-specifier braced-init-list |
| // |
| DeclSpec DS(AttrFactory); |
| |
| ParseCXXSimpleTypeSpecifier(DS); |
| if (Tok.isNot(tok::l_paren) && |
| (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace))) |
| return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) |
| << DS.getSourceRange()); |
| |
| if (Tok.is(tok::l_brace)) |
| Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); |
| |
| Res = ParseCXXTypeConstructExpression(DS); |
| break; |
| } |
| |
| 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(ParseKind, isAddressOfOperand, NotCastExpr, |
| isTypeCast, isVectorLiteral, |
| NotPrimaryExpression); |
| |
| Token Next = NextToken(); |
| if (Next.is(tok::annot_template_id)) { |
| TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); |
| 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=*/nullptr, |
| /*ObjectHadErrors=*/false, |
| /*EnteringContext=*/false); |
| AnnotateTemplateIdTokenAsType(SS); |
| return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, |
| isTypeCast, isVectorLiteral, |
| NotPrimaryExpression); |
| } |
| } |
| |
| // Parse as an id-expression. |
| Res = ParseCXXIdExpression(isAddressOfOperand); |
| break; |
| } |
| |
| case tok::annot_template_id: { // [C++] template-id |
| TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); |
| 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. |
| CXXScopeSpec SS; |
| AnnotateTemplateIdTokenAsType(SS); |
| return ParseCastExpression(ParseKind, isAddressOfOperand, |
| NotCastExpr, isTypeCast, isVectorLiteral, |
| NotPrimaryExpression); |
| } |
| |
| // Fall through to treat the template-id as an id-expression. |
| LLVM_FALLTHROUGH; |
| } |
| |
| case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id |
| Res = ParseCXXIdExpression(isAddressOfOperand); |
| break; |
| |
| 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(ParseKind, isAddressOfOperand, isTypeCast, |
| isVectorLiteral, NotPrimaryExpression); |
| |
| // ::new -> [C++] new-expression |
| // ::delete -> [C++] delete-expression |
| SourceLocation CCLoc = ConsumeToken(); |
| if (Tok.is(tok::kw_new)) { |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXNewExpression(true, CCLoc); |
| AllowSuffix = false; |
| break; |
| } |
| if (Tok.is(tok::kw_delete)) { |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXDeleteExpression(true, CCLoc); |
| AllowSuffix = false; |
| break; |
| } |
| |
| // 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 |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXNewExpression(false, Tok.getLocation()); |
| AllowSuffix = false; |
| break; |
| |
| case tok::kw_delete: // [C++] delete-expression |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseCXXDeleteExpression(false, Tok.getLocation()); |
| AllowSuffix = false; |
| break; |
| |
| case tok::kw_requires: // [C++2a] requires-expression |
| Res = ParseRequiresExpression(); |
| AllowSuffix = false; |
| break; |
| |
| case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); |
| SourceLocation KeyLoc = ConsumeToken(); |
| BalancedDelimiterTracker T(*this, tok::l_paren); |
| |
| if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) |
| return ExprError(); |
| // C++11 [expr.unary.noexcept]p1: |
| // The noexcept operator determines whether the evaluation of its operand, |
| // which is an unevaluated operand, can throw an exception. |
| EnterExpressionEvaluationContext Unevaluated( |
| Actions, Sema::ExpressionEvaluationContext::Unevaluated); |
| Res = ParseExpression(); |
| |
| T.consumeClose(); |
| |
| if (!Res.isInvalid()) |
| Res = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Res.get(), |
| T.getCloseLocation()); |
| AllowSuffix = false; |
| break; |
| } |
| |
| #define TYPE_TRAIT(N,Spelling,K) \ |
| case tok::kw_##Spelling: |
| #include "clang/Basic/TokenKinds.def" |
| Res = ParseTypeTrait(); |
| break; |
| |
| case tok::kw___array_rank: |
| case tok::kw___array_extent: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseArrayTypeTrait(); |
| break; |
| |
| case tok::kw___is_lvalue_expr: |
| case tok::kw___is_rvalue_expr: |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseExpressionTrait(); |
| break; |
| |
| case tok::at: { |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| SourceLocation AtLoc = ConsumeToken(); |
| return ParseObjCAtExpression(AtLoc); |
| } |
| case tok::caret: |
| Res = ParseBlockLiteralExpression(); |
| break; |
| case tok::code_completion: { |
| cutOffParsing(); |
| Actions.CodeCompleteExpression(getCurScope(), |
| PreferredType.get(Tok.getLocation())); |
| return ExprError(); |
| } |
| case tok::l_square: |
| if (getLangOpts().CPlusPlus11) { |
| if (getLangOpts().ObjC) { |
| // C++11 lambda expressions and Objective-C message sends both start with a |
| // square bracket. There are three possibilities here: |
| // we have a valid lambda expression, we have an invalid lambda |
| // expression, or we have something that doesn't appear to be a lambda. |
| // If we're in the last case, we fall back to ParseObjCMessageExpression. |
| Res = TryParseLambdaExpression(); |
| if (!Res.isInvalid() && !Res.get()) { |
| // We assume Objective-C++ message expressions are not |
| // primary-expressions. |
| if (NotPrimaryExpression) |
| *NotPrimaryExpression = true; |
| Res = ParseObjCMessageExpression(); |
| } |
| break; |
| } |
| Res = ParseLambdaExpression(); |
| break; |
| } |
| if (getLangOpts().ObjC) { |
| Res = ParseObjCMessageExpression(); |
| break; |
| } |
| LLVM_FALLTHROUGH; |
| default: |
| NotCastExpr = true; |
| return ExprError(); |
| } |
| |
| // Check to see whether Res is a function designator only. If it is and we |
| // are compiling for OpenCL, we need to return an error as this implies |
| // that the address of the function is being taken, which is illegal in CL. |
| |
| if (ParseKind == PrimaryExprOnly) |
| // This is strictly a primary-expression - no postfix-expr pieces should be |
| // parsed. |
| return Res; |
| |
| if (!AllowSuffix) { |
| // FIXME: Don't parse a primary-expression suffix if we encountered a parse |
| // error already. |
| if (Res.isInvalid()) |
| return Res; |
| |
| switch (Tok.getKind()) { |
| case tok::l_square: |
| case tok::l_paren: |
| case tok::plusplus: |
| case tok::minusminus: |
| // "expected ';'" or similar is probably the right diagnostic here. Let |
| // the caller decide what to do. |
| if (Tok.isAtStartOfLine()) |
| return Res; |
| |
| LLVM_FALLTHROUGH; |
| case tok::period: |
| case tok::arrow: |
| break; |
| |
| default: |
| return Res; |
| } |
| |
| // This was a unary-expression for which a postfix-expression suffix is |
| // not permitted by the grammar (eg, a sizeof expression or |
| // new-expression or similar). Diagnose but parse the suffix anyway. |
| Diag(Tok.getLocation(), diag::err_postfix_after_unary_requires_parens) |
| << Tok.getKind() << Res.get()->getSourceRange() |
| << FixItHint::CreateInsertion(Res.get()->getBeginLoc(), "(") |
| << FixItHint::CreateInsertion(PP.getLocForEndOfToken(PrevTokLocation), |
| ")"); |
| } |
| |
| // These can be followed by postfix-expr pieces. |
| PreferredType = SavedType; |
| Res = ParsePostfixExpressionSuffix(Res); |
| if (getLangOpts().OpenCL && |
| !getActions().getOpenCLOptions().isAvailableOption( |
| "__cl_clang_function_pointers", getLangOpts())) |
| if (Expr *PostfixExpr = Res.get()) { |
| QualType Ty = PostfixExpr->getType(); |
| if (!Ty.isNull() && Ty->isFunctionType()) { |
| Diag(PostfixExpr->getExprLoc(), |
| diag::err_opencl_taking_function_address_parser); |
| return ExprError(); |
| } |
| } |
| |
| return Res; |
| } |
| |
| /// Once the leading part of a postfix-expression is parsed, this |
| /// method parses any suffixes that apply. |
| /// |
| /// \verbatim |
| /// postfix-expression: [C99 6.5.2] |
| /// primary-expression |
| /// postfix-expression '[' expression ']' |
| /// postfix-expression '[' braced-init-list ']' |
| /// 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 ...[opt] |
| /// argument-expression-list ',' assignment-expression ...[opt] |
| /// \endverbatim |
| ExprResult |
| Parser::ParsePostfixExpressionSuffix(ExprResult 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; |
| auto SavedType = PreferredType; |
| while (1) { |
| // Each iteration relies on preferred type for the whole expression. |
| PreferredType = SavedType; |
| switch (Tok.getKind()) { |
| case tok::code_completion: |
| if (InMessageExpression) |
| return LHS; |
| |
| cutOffParsing(); |
| Actions.CodeCompletePostfixExpression( |
| getCurScope(), LHS, PreferredType.get(Tok.getLocation())); |
| return ExprError(); |
| |
| case tok::identifier: |
| // If we see identifier: after an expression, and we're not already in a |
| // message send, then this is probably a message send with a missing |
| // opening bracket '['. |
| if (getLangOpts().ObjC && !InMessageExpression && |
| (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { |
| LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), |
| nullptr, LHS.get()); |
| break; |
| } |
| // Fall through; this isn't a message send. |
| LLVM_FALLTHROUGH; |
| |
| default: // Not a postfix-expression suffix. |
| return LHS; |
| case tok::l_square: { // postfix-expression: p-e '[' expression ']' |
| // If we have a array postfix expression that starts on a new line and |
| // Objective-C is enabled, it is highly likely that the user forgot a |
| // semicolon after the base expression and that the array postfix-expr is |
| // actually another message send. In this case, do some look-ahead to see |
| // if the contents of the square brackets are obviously not a valid |
| // expression and recover by pretending there is no suffix. |
| if (getLangOpts().ObjC && Tok.isAtStartOfLine() && |
| isSimpleObjCMessageExpression()) |
| return LHS; |
| |
| // Reject array indices starting with a lambda-expression. '[[' is |
| // reserved for attributes. |
| if (CheckProhibitedCXX11Attribute()) { |
| (void)Actions.CorrectDelayedTyposInExpr(LHS); |
| return ExprError(); |
| } |
| |
| BalancedDelimiterTracker T(*this, tok::l_square); |
| T.consumeOpen(); |
| Loc = T.getOpenLocation(); |
| ExprResult Idx, Length, Stride; |
| SourceLocation ColonLocFirst, ColonLocSecond; |
| PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get()); |
| if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { |
| Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); |
| Idx = ParseBraceInitializer(); |
| } else if (getLangOpts().OpenMP) { |
| ColonProtectionRAIIObject RAII(*this); |
| // Parse [: or [ expr or [ expr : |
| if (!Tok.is(tok::colon)) { |
| // [ expr |
| Idx = ParseExpression(); |
| } |
| if (Tok.is(tok::colon)) { |
| // Consume ':' |
| ColonLocFirst = ConsumeToken(); |
| if (Tok.isNot(tok::r_square) && |
| (getLangOpts().OpenMP < 50 || |
| ((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50)))) |
| Length = ParseExpression(); |
| } |
| if (getLangOpts().OpenMP >= 50 && |
| (OMPClauseKind == llvm::omp::Clause::OMPC_to || |
| OMPClauseKind == llvm::omp::Clause::OMPC_from) && |
| Tok.is(tok::colon)) { |
| // Consume ':' |
| ColonLocSecond = ConsumeToken(); |
| if (Tok.isNot(tok::r_square)) { |
| Stride = ParseExpression(); |
| } |
| } |
| } else |
| Idx = ParseExpression(); |
| |
| SourceLocation RLoc = Tok.getLocation(); |
| |
| LHS = Actions.CorrectDelayedTyposInExpr(LHS); |
| Idx = Actions.CorrectDelayedTyposInExpr(Idx); |
| Length = Actions.CorrectDelayedTyposInExpr(Length); |
| if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && |
| !Stride.isInvalid() && Tok.is(tok::r_square)) { |
| if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) { |
| LHS = Actions.ActOnOMPArraySectionExpr( |
| LHS.get(), Loc, Idx.get(), ColonLocFirst, ColonLocSecond, |
| Length.get(), Stride.get(), RLoc); |
| } else { |
| LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, |
| Idx.get(), RLoc); |
| } |
| } else { |
| LHS = ExprError(); |
| Idx = ExprError(); |
| } |
| |
| // Match the ']'. |
| T.consumeClose(); |
| break; |
| } |
| |
| case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')' |
| case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>' |
| // '(' argument-expression-list[opt] ')' |
| tok::TokenKind OpKind = Tok.getKind(); |
| InMessageExpressionRAIIObject InMessage(*this, false); |
| |
| Expr *ExecConfig = nullptr; |
| |
| BalancedDelimiterTracker PT(*this, tok::l_paren); |
| |
| if (OpKind == tok::lesslessless) { |
| ExprVector ExecConfigExprs; |
| CommaLocsTy ExecConfigCommaLocs; |
| SourceLocation OpenLoc = ConsumeToken(); |
| |
| if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { |
| (void)Actions.CorrectDelayedTyposInExpr(LHS); |
| LHS = ExprError(); |
| } |
| |
| SourceLocation CloseLoc; |
| if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) { |
| } else if (LHS.isInvalid()) { |
| SkipUntil(tok::greatergreatergreater, StopAtSemi); |
| } else { |
| // There was an error closing the brackets |
| Diag(Tok, diag::err_expected) << tok::greatergreatergreater; |
| Diag(OpenLoc, diag::note_matching) << tok::lesslessless; |
| SkipUntil(tok::greatergreatergreater, StopAtSemi); |
| LHS = ExprError(); |
| } |
| |
| if (!LHS.isInvalid()) { |
| if (ExpectAndConsume(tok::l_paren)) |
| LHS = ExprError(); |
| else |
| Loc = PrevTokLocation; |
| } |
| |
| if (!LHS.isInvalid()) { |
| ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), |
| OpenLoc, |
| ExecConfigExprs, |
| CloseLoc); |
| if (ECResult.isInvalid()) |
| LHS = ExprError(); |
| else |
| ExecConfig = ECResult.get(); |
| } |
| } else { |
| PT.consumeOpen(); |
| Loc = PT.getOpenLocation(); |
| } |
| |
| ExprVector ArgExprs; |
| CommaLocsTy CommaLocs; |
| auto RunSignatureHelp = [&]() -> QualType { |
| QualType PreferredType = Actions.ProduceCallSignatureHelp( |
| getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); |
| CalledSignatureHelp = true; |
| return PreferredType; |
| }; |
| if (OpKind == tok::l_paren || !LHS.isInvalid()) { |
| if (Tok.isNot(tok::r_paren)) { |
| if (ParseExpressionList(ArgExprs, CommaLocs, [&] { |
| PreferredType.enterFunctionArgument(Tok.getLocation(), |
| RunSignatureHelp); |
| })) { |
| (void)Actions.CorrectDelayedTyposInExpr(LHS); |
| // If we got an error when parsing expression list, we don't call |
| // the CodeCompleteCall handler inside the parser. So call it here |
| // to make sure we get overload suggestions even when we are in the |
| // middle of a parameter. |
| if (PP.isCodeCompletionReached() && !CalledSignatureHelp) |
| RunSignatureHelp(); |
| LHS = ExprError(); |
| } else if (LHS.isInvalid()) { |
| for (auto &E : ArgExprs) |
| Actions.CorrectDelayedTyposInExpr(E); |
| } |
| } |
| } |
| |
| // Match the ')'. |
| if (LHS.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| } else if (Tok.isNot(tok::r_paren)) { |
| bool HadDelayedTypo = false; |
| if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get()) |
| HadDelayedTypo = true; |
| for (auto &E : ArgExprs) |
| if (Actions.CorrectDelayedTyposInExpr(E).get() != E) |
| HadDelayedTypo = true; |
| // If there were delayed typos in the LHS or ArgExprs, call SkipUntil |
| // instead of PT.consumeClose() to avoid emitting extra diagnostics for |
| // the unmatched l_paren. |
| if (HadDelayedTypo) |
| SkipUntil(tok::r_paren, StopAtSemi); |
| else |
| PT.consumeClose(); |
| LHS = ExprError(); |
| } else { |
| assert( |
| (ArgExprs.size() == 0 || ArgExprs.size() - 1 == CommaLocs.size()) && |
| "Unexpected number of commas!"); |
| Expr *Fn = LHS.get(); |
| SourceLocation RParLoc = Tok.getLocation(); |
| LHS = Actions.ActOnCallExpr(getCurScope(), Fn, Loc, ArgExprs, RParLoc, |
| ExecConfig); |
| if (LHS.isInvalid()) { |
| ArgExprs.insert(ArgExprs.begin(), Fn); |
| LHS = |
| Actions.CreateRecoveryExpr(Fn->getBeginLoc(), RParLoc, ArgExprs); |
| } |
| PT.consumeClose(); |
| } |
| |
| 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; |
| ParsedType ObjectType; |
| bool MayBePseudoDestructor = false; |
| Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; |
| |
| PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); |
| |
| if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { |
| Expr *Base = OrigLHS; |
| const Type* BaseType = Base->getType().getTypePtrOrNull(); |
| if (BaseType && Tok.is(tok::l_paren) && |
| (BaseType->isFunctionType() || |
| BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) { |
| Diag(OpLoc, diag::err_function_is_not_record) |
| << OpKind << Base->getSourceRange() |
| << FixItHint::CreateRemoval(OpLoc); |
| return ParsePostfixExpressionSuffix(Base); |
| } |
| |
| LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, OpLoc, |
| OpKind, ObjectType, |
| MayBePseudoDestructor); |
| if (LHS.isInvalid()) { |
| // Clang will try to perform expression based completion as a |
| // fallback, which is confusing in case of member references. So we |
| // stop here without any completions. |
| if (Tok.is(tok::code_completion)) { |
| cutOffParsing(); |
| return ExprError(); |
| } |
| break; |
| } |
| ParseOptionalCXXScopeSpecifier( |
| SS, ObjectType, LHS.get() && LHS.get()->containsErrors(), |
| /*EnteringContext=*/false, &MayBePseudoDestructor); |
| if (SS.isNotEmpty()) |
| ObjectType = nullptr; |
| } |
| |
| if (Tok.is(tok::code_completion)) { |
| tok::TokenKind CorrectedOpKind = |
| OpKind == tok::arrow ? tok::period : tok::arrow; |
| ExprResult CorrectedLHS(/*Invalid=*/true); |
| if (getLangOpts().CPlusPlus && OrigLHS) { |
| // FIXME: Creating a TentativeAnalysisScope from outside Sema is a |
| // hack. |
| Sema::TentativeAnalysisScope Trap(Actions); |
| CorrectedLHS = Actions.ActOnStartCXXMemberReference( |
| getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType, |
| MayBePseudoDestructor); |
| } |
| |
| Expr *Base = LHS.get(); |
| Expr *CorrectedBase = CorrectedLHS.get(); |
| if (!CorrectedBase && !getLangOpts().CPlusPlus) |
| CorrectedBase = Base; |
| |
| // Code completion for a member access expression. |
| cutOffParsing(); |
| Actions.CodeCompleteMemberReferenceExpr( |
| getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, |
| Base && ExprStatementTokLoc == Base->getBeginLoc(), |
| PreferredType.get(Tok.getLocation())); |
| |
| return ExprError(); |
| } |
| |
| if (MayBePseudoDestructor && !LHS.isInvalid()) { |
| LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS, |
| ObjectType); |
| break; |
| } |
| |
| // Either the action has told us 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. |
| // Allow explicit constructor calls in Microsoft mode. |
| // FIXME: Add support for explicit call of template constructor. |
| SourceLocation TemplateKWLoc; |
| UnqualifiedId Name; |
| if (getLangOpts().ObjC && OpKind == tok::period && |
| Tok.is(tok::kw_class)) { |
| // Objective-C++: |
| // After a '.' in a member access expression, treat the keyword |
| // 'class' as if it were an identifier. |
| // |
| // This hack allows property access to the 'class' method because it is |
| // such a common method name. For other C++ keywords that are |
| // Objective-C method names, one must use the message send syntax. |
| IdentifierInfo *Id = Tok.getIdentifierInfo(); |
| SourceLocation Loc = ConsumeToken(); |
| Name.setIdentifier(Id, Loc); |
| } else if (ParseUnqualifiedId( |
| SS, ObjectType, LHS.get() && LHS.get()->containsErrors(), |
| /*EnteringContext=*/false, |
| /*AllowDestructorName=*/true, |
| /*AllowConstructorName=*/ |
| getLangOpts().MicrosoftExt && SS.isNotEmpty(), |
| /*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) { |
| (void)Actions.CorrectDelayedTyposInExpr(LHS); |
| LHS = ExprError(); |
| } |
| |
| if (!LHS.isInvalid()) |
| LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, |
| OpKind, SS, TemplateKWLoc, Name, |
| CurParsedObjCImpl ? CurParsedObjCImpl->Dcl |
| : nullptr); |
| if (!LHS.isInvalid()) { |
| if (Tok.is(tok::less)) |
| checkPotentialAngleBracket(LHS); |
| } else if (OrigLHS && Name.isValid()) { |
| // Preserve the LHS if the RHS is an invalid member. |
| LHS = Actions.CreateRecoveryExpr(OrigLHS->getBeginLoc(), |
| Name.getEndLoc(), {OrigLHS}); |
| } |
| break; |
| } |
| case tok::plusplus: // postfix-expression: postfix-expression '++' |
| case tok::minusminus: // postfix-expression: postfix-expression '--' |
| if (!LHS.isInvalid()) { |
| Expr *Arg = LHS.get(); |
| LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), |
| Tok.getKind(), Arg); |
| if (LHS.isInvalid()) |
| LHS = Actions.CreateRecoveryExpr(Arg->getBeginLoc(), |
| Tok.getLocation(), Arg); |
| } |
| ConsumeToken(); |
| break; |
| } |
| } |
| } |
| |
| /// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ |
| /// vec_step 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). |
| /// |
| /// \verbatim |
| /// unary-expression: [C99 6.5.3] |
| /// 'sizeof' unary-expression |
| /// 'sizeof' '(' type-name ')' |
| /// [GNU] '__alignof' unary-expression |
| /// [GNU] '__alignof' '(' type-name ')' |
| /// [C11] '_Alignof' '(' type-name ')' |
| /// [C++0x] 'alignof' '(' type-id ')' |
| /// |
| /// [GNU] typeof-specifier: |
| /// typeof ( expressions ) |
| /// typeof ( type-name ) |
| /// [GNU/C++] typeof unary-expression |
| /// |
| /// [OpenCL 1.1 6.11.12] vec_step built-in function: |
| /// vec_step ( expressions ) |
| /// vec_step ( type-name ) |
| /// \endverbatim |
| ExprResult |
| Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, |
| bool &isCastExpr, |
| ParsedType &CastTy, |
| SourceRange &CastRange) { |
| |
| assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, |
| tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, |
| tok::kw___builtin_omp_required_simd_align) && |
| "Not a typeof/sizeof/alignof/vec_step expression!"); |
| |
| ExprResult Operand; |
| |
| // If the operand doesn't start with an '(', it must be an expression. |
| if (Tok.isNot(tok::l_paren)) { |
| // If construct allows a form without parenthesis, user may forget to put |
| // pathenthesis around type name. |
| if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, |
| tok::kw__Alignof)) { |
| if (isTypeIdUnambiguously()) { |
| DeclSpec DS(AttrFactory); |
| ParseSpecifierQualifierList(DS); |
| Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); |
| ParseDeclarator(DeclaratorInfo); |
| |
| SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); |
| SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation); |
| if (LParenLoc.isInvalid() || RParenLoc.isInvalid()) { |
| Diag(OpTok.getLocation(), |
| diag::err_expected_parentheses_around_typename) |
| << OpTok.getName(); |
| } else { |
| Diag(LParenLoc, diag::err_expected_parentheses_around_typename) |
| << OpTok.getName() << FixItHint::CreateInsertion(LParenLoc, "(") |
| << FixItHint::CreateInsertion(RParenLoc, ")"); |
| } |
| isCastExpr = true; |
| return ExprEmpty(); |
| } |
| } |
| |
| isCastExpr = false; |
| if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { |
| Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo() |
| << tok::l_paren; |
| return ExprError(); |
| } |
| |
| Operand = ParseCastExpression(UnaryExprOnly); |
| } 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; |
| |
| Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, |
| false, 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 (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { |
| // GNU typeof in C requires the expression to be parenthesized. Not so for |
| // sizeof/alignof or in C++. Therefore, the parenthesized expression is |
| // the start of a unary-expression, but doesn't include any postfix |
| // pieces. Parse these now if present. |
| if (!Operand.isInvalid()) |
| Operand = ParsePostfixExpressionSuffix(Operand.get()); |
| } |
| } |
| |
| // If we get here, the operand to the typeof/sizeof/alignof was an expression. |
| isCastExpr = false; |
| return Operand; |
| } |
| |
| /// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id as |
| /// a parameter. |
| ExprResult Parser::ParseSYCLUniqueStableNameExpression() { |
| assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) && |
| "Not __builtin_sycl_unique_stable_name"); |
| |
| SourceLocation OpLoc = ConsumeToken(); |
| BalancedDelimiterTracker T(*this, tok::l_paren); |
| |
| // __builtin_sycl_unique_stable_name expressions are always parenthesized. |
| if (T.expectAndConsume(diag::err_expected_lparen_after, |
| "__builtin_sycl_unique_stable_name")) |
| return ExprError(); |
| |
| TypeResult Ty = ParseTypeName(); |
| |
| if (Ty.isInvalid()) { |
| T.skipToEnd(); |
| return ExprError(); |
| } |
| |
| if (T.consumeClose()) |
| return ExprError(); |
| |
| return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(), |
| T.getCloseLocation(), Ty.get()); |
| } |
| |
| /// Parse a sizeof or alignof expression. |
| /// |
| /// \verbatim |
| /// unary-expression: [C99 6.5.3] |
| /// 'sizeof' unary-expression |
| /// 'sizeof' '(' type-name ')' |
| /// [C++11] 'sizeof' '...' '(' identifier ')' |
| /// [GNU] '__alignof' unary-expression |
| /// [GNU] '__alignof' '(' type-name ')' |
| /// [C11] '_Alignof' '(' type-name ')' |
| /// [C++11] 'alignof' '(' type-id ')' |
| /// \endverbatim |
| ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { |
| assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, |
| tok::kw__Alignof, tok::kw_vec_step, |
| tok::kw___builtin_omp_required_simd_align) && |
| "Not a sizeof/alignof/vec_step expression!"); |
| Token OpTok = Tok; |
| ConsumeToken(); |
| |
| // [C++11] 'sizeof' '...' '(' identifier ')' |
| if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) { |
| SourceLocation EllipsisLoc = ConsumeToken(); |
| SourceLocation LParenLoc, RParenLoc; |
| IdentifierInfo *Name = nullptr; |
| SourceLocation NameLoc; |
| if (Tok.is(tok::l_paren)) { |
| BalancedDelimiterTracker T(*this, tok::l_paren); |
| T.consumeOpen(); |
| LParenLoc = T.getOpenLocation(); |
| if (Tok.is(tok::identifier)) { |
| Name = Tok.getIdentifierInfo(); |
| NameLoc = ConsumeToken(); |
| T.consumeClose(); |
| RParenLoc = T.getCloseLocation(); |
| if (RParenLoc.isInvalid()) |
| RParenLoc = PP.getLocForEndOfToken(NameLoc); |
| } else { |
| Diag(Tok, diag::err_expected_parameter_pack); |
| SkipUntil(tok::r_paren, StopAtSemi); |
| } |
| } else if (Tok.is(tok::identifier)) { |
| Name = Tok.getIdentifierInfo(); |
| NameLoc = ConsumeToken(); |
| LParenLoc = PP.getLocForEndOfToken(EllipsisLoc); |
| RParenLoc = PP.getLocForEndOfToken(NameLoc); |
| Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack) |
| << Name |
| << FixItHint::CreateInsertion(LParenLoc, "(") |
| << FixItHint::CreateInsertion(RParenLoc, ")"); |
| } else { |
| Diag(Tok, diag::err_sizeof_parameter_pack); |
| } |
| |
| if (!Name) |
| return ExprError(); |
| |
| EnterExpressionEvaluationContext Unevaluated( |
| Actions, Sema::ExpressionEvaluationContext::Unevaluated, |
| Sema::ReuseLambdaContextDecl); |
| |
| return Actions.ActOnSizeofParameterPackExpr(getCurScope(), |
| OpTok.getLocation(), |
| *Name, NameLoc, |
| RParenLoc); |
| } |
| |
| if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) |
| Diag(OpTok, diag::warn_cxx98_compat_alignof); |
| |
| EnterExpressionEvaluationContext Unevaluated( |
| Actions, Sema::ExpressionEvaluationContext::Unevaluated, |
| Sema::ReuseLambdaContextDecl); |
| |
| bool isCastExpr; |
| ParsedType CastTy; |
| SourceRange CastRange; |
| ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, |
| isCastExpr, |
| CastTy, |
| CastRange); |
| |
| UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; |
| if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) |
| ExprKind = UETT_AlignOf; |
| else if (OpTok.is(tok::kw___alignof)) |
| ExprKind = UETT_PreferredAlignOf; |
| else if (OpTok.is(tok::kw_vec_step)) |
| ExprKind = UETT_VecStep; |
| else if (OpTok.is(tok::kw___builtin_omp_required_simd_align)) |
| ExprKind = UETT_OpenMPRequiredSimdAlign; |
| |
| if (isCastExpr) |
| return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), |
| ExprKind, |
| /*IsType=*/true, |
| CastTy.getAsOpaquePtr(), |
| CastRange); |
| |
| if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) |
| Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo(); |
| |
| // If we get here, the operand to the sizeof/alignof was an expression. |
| if (!Operand.isInvalid()) |
| Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), |
| ExprKind, |
| /*IsType=*/false, |
| Operand.get(), |
| CastRange); |
| return Operand; |
| } |
| |
| /// ParseBuiltinPrimaryExpression |
| /// |
| /// \verbatim |
| /// 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] '__builtin_FILE' '(' ')' |
| /// [GNU] '__builtin_FUNCTION' '(' ')' |
| /// [GNU] '__builtin_LINE' '(' ')' |
| /// [CLANG] '__builtin_COLUMN' '(' ')' |
| /// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' |
| /// |
| /// [GNU] offsetof-member-designator: |
| /// [GNU] identifier |
| /// [GNU] offsetof-member-designator '.' identifier |
| /// [GNU] offsetof-member-designator '[' expression ']' |
| /// \endverbatim |
| ExprResult Parser::ParseBuiltinPrimaryExpression() { |
| ExprResult Res; |
| 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_after) << BuiltinII |
| << tok::l_paren); |
| |
| BalancedDelimiterTracker PT(*this, tok::l_paren); |
| PT.consumeOpen(); |
| |
| // TODO: Build AST. |
| |
| switch (T) { |
| default: llvm_unreachable("Not a builtin primary expression!"); |
| case tok::kw___builtin_va_arg: { |
| ExprResult Expr(ParseAssignmentExpression()); |
| |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| Expr = ExprError(); |
| } |
| |
| TypeResult Ty = ParseTypeName(); |
| |
| if (Tok.isNot(tok::r_paren)) { |
| Diag(Tok, diag::err_expected) << tok::r_paren; |
| Expr = ExprError(); |
| } |
| |
| if (Expr.isInvalid() || Ty.isInvalid()) |
| Res = ExprError(); |
| else |
| Res = Actions.ActOnVAArg(StartLoc, Expr.get(), Ty.get(), ConsumeParen()); |
| break; |
| } |
| case tok::kw___builtin_offsetof: { |
| SourceLocation TypeLoc = Tok.getLocation(); |
| TypeResult Ty = ParseTypeName(); |
| if (Ty.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| // We must have at least one identifier here. |
| if (Tok.isNot(tok::identifier)) { |
| Diag(Tok, diag::err_expected) << tok::identifier; |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| // Keep track of the various subcomponents we see. |
| SmallVector<Sema::OffsetOfComponent, 4> Comps; |
| |
| Comps.push_back(Sema::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(Sema::OffsetOfComponent()); |
| Comps.back().isBrackets = false; |
| Comps.back().LocStart = ConsumeToken(); |
| |
| if (Tok.isNot(tok::identifier)) { |
| Diag(Tok, diag::err_expected) << tok::identifier; |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); |
| Comps.back().LocEnd = ConsumeToken(); |
| |
| } else if (Tok.is(tok::l_square)) { |
| if (CheckProhibitedCXX11Attribute()) |
| return ExprError(); |
| |
| // offsetof-member-designator: offsetof-member-design '[' expression ']' |
| Comps.push_back(Sema::OffsetOfComponent()); |
| Comps.back().isBrackets = true; |
| BalancedDelimiterTracker ST(*this, tok::l_square); |
| ST.consumeOpen(); |
| Comps.back().LocStart = ST.getOpenLocation(); |
| Res = ParseExpression(); |
| if (Res.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return Res; |
| } |
| Comps.back().U.E = Res.get(); |
| |
| ST.consumeClose(); |
| Comps.back().LocEnd = ST.getCloseLocation(); |
| } else { |
| if (Tok.isNot(tok::r_paren)) { |
| PT.consumeClose(); |
| Res = ExprError(); |
| } else if (Ty.isInvalid()) { |
| Res = ExprError(); |
| } else { |
| PT.consumeClose(); |
| Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc, |
| Ty.get(), Comps, |
| PT.getCloseLocation()); |
| } |
| break; |
| } |
| } |
| break; |
| } |
| case tok::kw___builtin_choose_expr: { |
| ExprResult Cond(ParseAssignmentExpression()); |
| if (Cond.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return Cond; |
| } |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| ExprResult Expr1(ParseAssignmentExpression()); |
| if (Expr1.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return Expr1; |
| } |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| ExprResult Expr2(ParseAssignmentExpression()); |
| if (Expr2.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return Expr2; |
| } |
| if (Tok.isNot(tok::r_paren)) { |
| Diag(Tok, diag::err_expected) << tok::r_paren; |
| return ExprError(); |
| } |
| Res = Actions.ActOnChooseExpr(StartLoc, Cond.get(), Expr1.get(), |
| Expr2.get(), ConsumeParen()); |
| break; |
| } |
| case tok::kw___builtin_astype: { |
| // The first argument is an expression to be converted, followed by a comma. |
| ExprResult Expr(ParseAssignmentExpression()); |
| if (Expr.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| // Second argument is the type to bitcast to. |
| TypeResult DestTy = ParseTypeName(); |
| if (DestTy.isInvalid()) |
| return ExprError(); |
| |
| // Attempt to consume the r-paren. |
| if (Tok.isNot(tok::r_paren)) { |
| Diag(Tok, diag::err_expected) << tok::r_paren; |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| Res = Actions.ActOnAsTypeExpr(Expr.get(), DestTy.get(), StartLoc, |
| ConsumeParen()); |
| break; |
| } |
| case tok::kw___builtin_convertvector: { |
| // The first argument is an expression to be converted, followed by a comma. |
| ExprResult Expr(ParseAssignmentExpression()); |
| if (Expr.isInvalid()) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| if (ExpectAndConsume(tok::comma)) { |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| // Second argument is the type to bitcast to. |
| TypeResult DestTy = ParseTypeName(); |
| if (DestTy.isInvalid()) |
| return ExprError(); |
| |
| // Attempt to consume the r-paren. |
| if (Tok.isNot(tok::r_paren)) { |
| Diag(Tok, diag::err_expected) << tok::r_paren; |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| |
| Res = Actions.ActOnConvertVectorExpr(Expr.get(), DestTy.get(), StartLoc, |
| ConsumeParen()); |
| break; |
| } |
| case tok::kw___builtin_COLUMN: |
| case tok::kw___builtin_FILE: |
| case tok::kw___builtin_FUNCTION: |
| case tok::kw___builtin_LINE: { |
| // Attempt to consume the r-paren. |
| if (Tok.isNot(tok::r_paren)) { |
| Diag(Tok, diag::err_expected) << tok::r_paren; |
| SkipUntil(tok::r_paren, StopAtSemi); |
| return ExprError(); |
| } |
| SourceLocExpr::IdentKind Kind = [&] { |
| switch (T) { |
| case tok::kw___builtin_FILE: |
| return SourceLocExpr::File; |
| case tok::kw___builtin_FUNCTION: |
| return SourceLocExpr::Function; |
| case tok::kw___builtin_LINE: |
| return SourceLocExpr::Line; |
| case tok::kw___builtin_COLUMN: |
| return SourceLocExpr::Column; |
| default: |
| llvm_unreachable("invalid keyword"); |
| } |
| }(); |
| Res = Actions.ActOnSourceLocExpr(Kind, StartLoc, ConsumeParen()); |
| break; |
| } |
| } |
| |
| if (Res.isInvalid()) |
| return ExprError(); |
| |
| // These can be followed by postfix-expr pieces because they are |
| // primary-expressions. |
| return ParsePostfixExpressionSuffix(Res.get()); |
| } |
| |
| bool Parser::tryParseOpenMPArrayShapingCastPart() { |
| assert(Tok.is(tok::l_square) && "Expected open bracket"); |
| bool ErrorFound = true; |
| TentativeParsingAction TPA(*this); |
| do { |
| if (Tok.isNot(tok::l_square)) |
| break; |
| // Consume '[' |
| ConsumeBracket(); |
| // Skip inner expression. |
| while (!SkipUntil(tok::r_square, tok::annot_pragma_openmp_end, |
| StopAtSemi | StopBeforeMatch)) |
| ; |
| if (Tok.isNot(tok::r_square)) |
| break; |
| // Consume ']' |
| ConsumeBracket(); |
| // Found ')' - done. |
| if (Tok.is(tok::r_paren)) { |
| ErrorFound = false; |
| break; |
| } |
| } while (Tok.isNot(tok::annot_pragma_openmp_end)); |
| TPA.Revert(); |
| return !ErrorFound; |
| } |
| |
| /// 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. |
| /// |
| /// \verbatim |
| /// 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 |
| /// [ARC] bridged-cast-expression |
| /// [ARC] bridged-cast-expression: |
| /// (__bridge type-name) cast-expression |
| /// (__bridge_transfer type-name) cast-expression |
| /// (__bridge_retained type-name) cast-expression |
| /// fold-expression: [C++1z] |
| /// '(' cast-expression fold-operator '...' ')' |
| /// '(' '...' fold-operator cast-expression ')' |
| /// '(' cast-expression fold-operator '...' |
| /// fold-operator cast-expression ')' |
| /// [OPENMP] Array shaping operation |
| /// '(' '[' expression ']' { '[' expression ']' } cast-expression |
| /// \endverbatim |
| ExprResult |
| Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, |
| bool isTypeCast, ParsedType &CastTy, |
| SourceLocation &RParenLoc) { |
| assert(Tok.is(tok::l_paren) && "Not a paren expr!"); |
| ColonProtectionRAIIObject ColonProtection(*this, false); |
| BalancedDelimiterTracker T(*this, tok::l_paren); |
| if (T.consumeOpen()) |
| return ExprError(); |
| SourceLocation OpenLoc = T.getOpenLocation(); |
| |
| PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc); |
| |
| ExprResult Result(true); |
| bool isAmbiguousTypeId; |
| CastTy = nullptr; |
| |
| if (Tok.is(tok::code_completion)) { |
| cutOffParsing(); |
| Actions.CodeCompleteExpression( |
| getCurScope(), PreferredType.get(Tok.getLocation()), |
| /*IsParenthesized=*/ExprType >= CompoundLiteral); |
| return ExprError(); |
| } |
| |
| // Diagnose use of bridge casts in non-arc mode. |
| bool BridgeCast = (getLangOpts().ObjC && |
| Tok.isOneOf(tok::kw___bridge, |
| tok::kw___bridge_transfer, |
| tok::kw___bridge_retained, |
| tok::kw___bridge_retain)); |
| if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { |
| if (!TryConsumeToken(tok::kw___bridge)) { |
| StringRef BridgeCastName = Tok.getName(); |
| SourceLocation BridgeKeywordLoc = ConsumeToken(); |
| if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) |
| Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) |
| << BridgeCastName |
| << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); |
| } |
| BridgeCast = false; |
| } |
| |
| // None of these cases should fall through with an invalid Result |
| // unless they've already reported an error. |
| if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { |
| Diag(Tok, diag::ext_gnu_statement_expr); |
| |
| checkCompoundToken(OpenLoc, tok::l_paren, CompoundToken::StmtExprBegin); |
| |
| if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) { |
| Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope)); |
| } else { |
| // Find the nearest non-record decl context. Variables declared in a |
| // statement expression behave as if they were declared in the enclosing |
| // function, block, or other code construct. |
| DeclContext *CodeDC = Actions.CurContext; |
| while (CodeDC->isRecord() || isa<EnumDecl>(CodeDC)) { |
| CodeDC = CodeDC->getParent(); |
| assert(CodeDC && !CodeDC->isFileContext() && |
| "statement expr not in code context"); |
| } |
| Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false); |
| |
| Actions.ActOnStartStmtExpr(); |
| |
| StmtResult Stmt(ParseCompoundStatement(true)); |
| ExprType = CompoundStmt; |
| |
| // If the substmt parsed correctly, build the AST node. |
| if (!Stmt.isInvalid()) { |
| Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(), |
| Tok.getLocation()); |
| } else { |
| Actions.ActOnStmtExprError(); |
| } |
| } |
| } else if (ExprType >= CompoundLiteral && BridgeCast) { |
| tok::TokenKind tokenKind = Tok.getKind(); |
| SourceLocation BridgeKeywordLoc = ConsumeToken(); |
| |
| // Parse an Objective-C ARC ownership cast expression. |
| ObjCBridgeCastKind Kind; |
| if (tokenKind == tok::kw___bridge) |
| Kind = OBC_
|