|  | //===--- 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)) { | 
|  | Actions.CodeCompleteExpression(getCurScope(), | 
|  | PreferredType.get(Tok.getLocation())); | 
|  | cutOffParsing(); | 
|  | 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::ConstantEvaluated); | 
|  | 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::ConstantEvaluated); | 
|  | 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())); | 
|  |  | 
|  | LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), | 
|  | OpToken.getKind(), LHS.get(), RHS.get()); | 
|  |  | 
|  | } else { | 
|  | LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, | 
|  | LHS.get(), TernaryMiddle.get(), | 
|  | RHS.get()); | 
|  | } | 
|  | // 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 | 
|  | ///         '__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; | 
|  |  | 
|  | // 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 return without invoking | 
|  | // ParsePostfixExpressionSuffix. | 
|  | 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); | 
|  |  | 
|  | 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: | 
|  | return ParseObjCBoolLiteral(); | 
|  |  | 
|  | case tok::kw_nullptr: | 
|  | Diag(Tok, diag::warn_cxx98_compat_nullptr); | 
|  | return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); | 
|  |  | 
|  | case tok::annot_primary_expr: | 
|  | Res = getExprAnnotation(Tok); | 
|  | 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) { | 
|  | Actions.CodeCompleteObjCClassPropertyRefExpr( | 
|  | getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); | 
|  | cutOffParsing(); | 
|  | 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::TypeNameContext); | 
|  | 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: | 
|  | return ParseAvailabilityCheckExpr(Tok.getLocation()); | 
|  | 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; | 
|  | return ParseBuiltinPrimaryExpression(); | 
|  | case tok::kw___null: | 
|  | return Actions.ActOnGNUNullExpr(ConsumeToken()); | 
|  |  | 
|  | 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()) | 
|  | Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), | 
|  | SavedKind, Res.get()); | 
|  | 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()) | 
|  | Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); | 
|  | 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()) | 
|  | Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); | 
|  | 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; | 
|  | return ParseUnaryExprOrTypeTraitExpression(); | 
|  | 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(); | 
|  | return Res; | 
|  | } | 
|  | case tok::kw_const_cast: | 
|  | case tok::kw_dynamic_cast: | 
|  | case tok::kw_reinterpret_cast: | 
|  | case tok::kw_static_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::annot_typename: | 
|  | if (isStartOfObjCClassMessageMissingOpenBracket()) { | 
|  | ParsedType 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::TypeNameContext); | 
|  | 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_signed: | 
|  | case tok::kw_unsigned: | 
|  | case tok::kw_half: | 
|  | case tok::kw_float: | 
|  | case tok::kw_double: | 
|  | case tok::kw__Float16: | 
|  | case tok::kw___float128: | 
|  | 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, nullptr, | 
|  | /*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; | 
|  | return ParseCXXNewExpression(true, CCLoc); | 
|  | } | 
|  | if (Tok.is(tok::kw_delete)) { | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | return ParseCXXDeleteExpression(true, CCLoc); | 
|  | } | 
|  |  | 
|  | // This is not a type name or scope specifier, it is an invalid expression. | 
|  | Diag(CCLoc, diag::err_expected_expression); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | case tok::kw_new: // [C++] new-expression | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | return ParseCXXNewExpression(false, Tok.getLocation()); | 
|  |  | 
|  | case tok::kw_delete: // [C++] delete-expression | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | return ParseCXXDeleteExpression(false, Tok.getLocation()); | 
|  |  | 
|  | 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); | 
|  | ExprResult Result = ParseExpression(); | 
|  |  | 
|  | T.consumeClose(); | 
|  |  | 
|  | if (!Result.isInvalid()) | 
|  | Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), | 
|  | Result.get(), T.getCloseLocation()); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | #define TYPE_TRAIT(N,Spelling,K) \ | 
|  | case tok::kw_##Spelling: | 
|  | #include "clang/Basic/TokenKinds.def" | 
|  | return ParseTypeTrait(); | 
|  |  | 
|  | case tok::kw___array_rank: | 
|  | case tok::kw___array_extent: | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | return ParseArrayTypeTrait(); | 
|  |  | 
|  | case tok::kw___is_lvalue_expr: | 
|  | case tok::kw___is_rvalue_expr: | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | return ParseExpressionTrait(); | 
|  |  | 
|  | case tok::at: { | 
|  | if (NotPrimaryExpression) | 
|  | *NotPrimaryExpression = true; | 
|  | SourceLocation AtLoc = ConsumeToken(); | 
|  | return ParseObjCAtExpression(AtLoc); | 
|  | } | 
|  | case tok::caret: | 
|  | Res = ParseBlockLiteralExpression(); | 
|  | break; | 
|  | case tok::code_completion: { | 
|  | Actions.CodeCompleteExpression(getCurScope(), | 
|  | PreferredType.get(Tok.getLocation())); | 
|  | cutOffParsing(); | 
|  | 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; | 
|  |  | 
|  | // These can be followed by postfix-expr pieces. | 
|  | PreferredType = SavedType; | 
|  | Res = ParsePostfixExpressionSuffix(Res); | 
|  | if (getLangOpts().OpenCL) | 
|  | 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; | 
|  |  | 
|  | Actions.CodeCompletePostfixExpression( | 
|  | getCurScope(), LHS, PreferredType.get(Tok.getLocation())); | 
|  | cutOffParsing(); | 
|  | 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; | 
|  | SourceLocation ColonLoc; | 
|  | 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 ':' | 
|  | ColonLoc = ConsumeToken(); | 
|  | if (Tok.isNot(tok::r_square)) | 
|  | Length = 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() && | 
|  | Tok.is(tok::r_square)) { | 
|  | if (ColonLoc.isValid()) { | 
|  | LHS = Actions.ActOnOMPArraySectionExpr(LHS.get(), Loc, Idx.get(), | 
|  | ColonLoc, Length.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!"); | 
|  | LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc, | 
|  | ArgExprs, Tok.getLocation(), | 
|  | ExecConfig); | 
|  | 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()) | 
|  | break; | 
|  |  | 
|  | ParseOptionalCXXScopeSpecifier(SS, ObjectType, | 
|  | /*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. | 
|  | Actions.CodeCompleteMemberReferenceExpr( | 
|  | getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, | 
|  | Base && ExprStatementTokLoc == Base->getBeginLoc(), | 
|  | PreferredType.get(Tok.getLocation())); | 
|  |  | 
|  | cutOffParsing(); | 
|  | 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, | 
|  | /*EnteringContext=*/false, | 
|  | /*AllowDestructorName=*/true, | 
|  | /*AllowConstructorName=*/ | 
|  | getLangOpts().MicrosoftExt && | 
|  | SS.isNotEmpty(), | 
|  | /*AllowDeductionGuide=*/false, | 
|  | ObjectType, &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() && Tok.is(tok::less)) | 
|  | checkPotentialAngleBracket(LHS); | 
|  | break; | 
|  | } | 
|  | case tok::plusplus:    // postfix-expression: postfix-expression '++' | 
|  | case tok::minusminus:  // postfix-expression: postfix-expression '--' | 
|  | if (!LHS.isInvalid()) { | 
|  | LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), | 
|  | Tok.getKind(), LHS.get()); | 
|  | } | 
|  | 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::TypeNameContext); | 
|  | ParseDeclarator(DeclaratorInfo); | 
|  |  | 
|  | SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); | 
|  | SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation); | 
|  | 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 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()); | 
|  | } | 
|  |  | 
|  | /// 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 ')' | 
|  | /// \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)) { | 
|  | Actions.CodeCompleteExpression( | 
|  | getCurScope(), PreferredType.get(Tok.getLocation()), | 
|  | /*IsParenthesized=*/ExprType >= CompoundLiteral); | 
|  | cutOffParsing(); | 
|  | 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); | 
|  |  | 
|  | 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(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_Bridge; | 
|  | else if (tokenKind == tok::kw___bridge_transfer) | 
|  | Kind = OBC_BridgeTransfer; | 
|  | else if (tokenKind == tok::kw___bridge_retained) | 
|  | Kind = OBC_BridgeRetained; | 
|  | else { | 
|  | // As a hopefully temporary workaround, allow __bridge_retain as | 
|  | // a synonym for __bridge_retained, but only in system headers. | 
|  | assert(tokenKind == tok::kw___bridge_retain); | 
|  | Kind = OBC_BridgeRetained; | 
|  | if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) | 
|  | Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain) | 
|  | << FixItHint::CreateReplacement(BridgeKeywordLoc, | 
|  | "__bridge_retained"); | 
|  | } | 
|  |  | 
|  | TypeResult Ty = ParseTypeName(); | 
|  | T.consumeClose(); | 
|  | ColonProtection.restore(); | 
|  | RParenLoc = T.getCloseLocation(); | 
|  |  | 
|  | PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); | 
|  | ExprResult SubExpr = ParseCastExpression(AnyCastExpr); | 
|  |  | 
|  | if (Ty.isInvalid() || SubExpr.isInvalid()) | 
|  | return ExprError(); | 
|  |  | 
|  | return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind, | 
|  | BridgeKeywordLoc, Ty.get(), | 
|  | RParenLoc, SubExpr.get()); | 
|  | } else if (ExprType >= CompoundLiteral && | 
|  | isTypeIdInParens(isAmbiguousTypeId)) { | 
|  |  | 
|  | // Otherwise, this is a compound literal expression or cast expression. | 
|  |  | 
|  | // In C++, if the type-id is ambiguous we disambiguate based on context. | 
|  | // If stopIfCastExpr is true the context is a typeof/sizeof/alignof | 
|  | // in which case we should treat it as type-id. | 
|  | // if stopIfCastExpr is false, we need to determine the context past the | 
|  | // parens, so we defer to ParseCXXAmbiguousParenExpression for that. | 
|  | if (isAmbiguousTypeId && !stopIfCastExpr) { | 
|  | ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T, | 
|  | ColonProtection); | 
|  | RParenLoc = T.getCloseLocation(); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | // Parse the type declarator. | 
|  | DeclSpec DS(AttrFactory); | 
|  | ParseSpecifierQualifierList(DS); | 
|  | Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); | 
|  | ParseDeclarator(DeclaratorInfo); | 
|  |  | 
|  | // If our type is followed by an identifier and either ':' or ']', then | 
|  | // this is probably an Objective-C message send where the leading '[' is | 
|  | // missing. Recover as if that were the case. | 
|  | if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && | 
|  | !InMessageExpression && getLangOpts().ObjC && | 
|  | (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { | 
|  | TypeResult Ty; | 
|  | { | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  | Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); | 
|  | } | 
|  | Result = ParseObjCMessageExpressionBody(SourceLocation(), | 
|  | SourceLocation(), | 
|  | Ty.get(), nullptr); | 
|  | } else { | 
|  | // Match the ')'. | 
|  | T.consumeClose(); | 
|  | ColonProtection.restore(); | 
|  | RParenLoc = T.getCloseLocation(); | 
|  | if (Tok.is(tok::l_brace)) { | 
|  | ExprType = CompoundLiteral; | 
|  | TypeResult Ty; | 
|  | { | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  | Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); | 
|  | } | 
|  | return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | // This could be OpenCL vector Literals | 
|  | if (getLangOpts().OpenCL) | 
|  | { | 
|  | TypeResult Ty; | 
|  | { | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  | Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); | 
|  | } | 
|  | if(Ty.isInvalid()) | 
|  | { | 
|  | return ExprError(); | 
|  | } | 
|  | QualType QT = Ty.get().get().getCanonicalType(); | 
|  | if (QT->isVectorType()) | 
|  | { | 
|  | // We parsed '(' vector-type-name ')' followed by '(' | 
|  |  | 
|  | // Parse the cast-expression that follows it next. | 
|  | // isVectorLiteral = true will make sure we don't parse any | 
|  | // Postfix expression yet | 
|  | Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, | 
|  | /*isAddressOfOperand=*/false, | 
|  | /*isTypeCast=*/IsTypeCast, | 
|  | /*isVectorLiteral=*/true); | 
|  |  | 
|  | if (!Result.isInvalid()) { | 
|  | Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, | 
|  | DeclaratorInfo, CastTy, | 
|  | RParenLoc, Result.get()); | 
|  | } | 
|  |  | 
|  | // After we performed the cast we can check for postfix-expr pieces. | 
|  | if (!Result.isInvalid()) { | 
|  | Result = ParsePostfixExpressionSuffix(Result); | 
|  | } | 
|  |  | 
|  | return Result; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ExprType == CastExpr) { | 
|  | // We parsed '(' type-name ')' and the thing after it wasn't a '{'. | 
|  |  | 
|  | if (DeclaratorInfo.isInvalidType()) | 
|  | return ExprError(); | 
|  |  | 
|  | // Note that this doesn't parse the subsequent cast-expression, it just | 
|  | // returns the parsed type to the callee. | 
|  | if (stopIfCastExpr) { | 
|  | TypeResult Ty; | 
|  | { | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  | Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); | 
|  | } | 
|  | CastTy = Ty.get(); | 
|  | return ExprResult(); | 
|  | } | 
|  |  | 
|  | // Reject the cast of super idiom in ObjC. | 
|  | if (Tok.is(tok::identifier) && getLangOpts().ObjC && | 
|  | Tok.getIdentifierInfo() == Ident_super && | 
|  | getCurScope()->isInObjcMethodScope() && | 
|  | GetLookAheadToken(1).isNot(tok::period)) { | 
|  | Diag(Tok.getLocation(), diag::err_illegal_super_cast) | 
|  | << SourceRange(OpenLoc, RParenLoc); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); | 
|  | // Parse the cast-expression that follows it next. | 
|  | // TODO: For cast expression with CastTy. | 
|  | Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, | 
|  | /*isAddressOfOperand=*/false, | 
|  | /*isTypeCast=*/IsTypeCast); | 
|  | if (!Result.isInvalid()) { | 
|  | Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, | 
|  | DeclaratorInfo, CastTy, | 
|  | RParenLoc, Result.get()); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | Diag(Tok, diag::err_expected_lbrace_in_compound_literal); | 
|  | return ExprError(); | 
|  | } | 
|  | } else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) && | 
|  | isFoldOperator(NextToken().getKind())) { | 
|  | ExprType = FoldExpr; | 
|  | return ParseFoldExpression(ExprResult(), T); | 
|  | } else if (isTypeCast) { | 
|  | // Parse the expression-list. | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  |  | 
|  | ExprVector ArgExprs; | 
|  | CommaLocsTy CommaLocs; | 
|  |  | 
|  | if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) { | 
|  | // FIXME: If we ever support comma expressions as operands to | 
|  | // fold-expressions, we'll need to allow multiple ArgExprs here. | 
|  | if (ExprType >= FoldExpr && ArgExprs.size() == 1 && | 
|  | isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { | 
|  | ExprType = FoldExpr; | 
|  | return ParseFoldExpression(ArgExprs[0], T); | 
|  | } | 
|  |  | 
|  | ExprType = SimpleExpr; | 
|  | Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), | 
|  | ArgExprs); | 
|  | } | 
|  | } else { | 
|  | InMessageExpressionRAIIObject InMessage(*this, false); | 
|  |  | 
|  | Result = ParseExpression(MaybeTypeCast); | 
|  | if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) { | 
|  | // Correct typos in non-C++ code earlier so that implicit-cast-like | 
|  | // expressions are parsed correctly. | 
|  | Result = Actions.CorrectDelayedTyposInExpr(Result); | 
|  | } | 
|  |  | 
|  | if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) && | 
|  | NextToken().is(tok::ellipsis)) { | 
|  | ExprType = FoldExpr; | 
|  | return ParseFoldExpression(Result, T); | 
|  | } | 
|  | ExprType = SimpleExpr; | 
|  |  | 
|  | // Don't build a paren expression unless we actually match a ')'. | 
|  | if (!Result.isInvalid() && Tok.is(tok::r_paren)) | 
|  | Result = | 
|  | Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.get()); | 
|  | } | 
|  |  | 
|  | // Match the ')'. | 
|  | if (Result.isInvalid()) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | T.consumeClose(); | 
|  | RParenLoc = T.getCloseLocation(); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name | 
|  | /// and we are at the left brace. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///       postfix-expression: [C99 6.5.2] | 
|  | ///         '(' type-name ')' '{' initializer-list '}' | 
|  | ///         '(' type-name ')' '{' initializer-list ',' '}' | 
|  | /// \endverbatim | 
|  | ExprResult | 
|  | Parser::ParseCompoundLiteralExpression(ParsedType Ty, | 
|  | SourceLocation LParenLoc, | 
|  | SourceLocation RParenLoc) { | 
|  | assert(Tok.is(tok::l_brace) && "Not a compound literal!"); | 
|  | if (!getLangOpts().C99)   // Compound literals don't exist in C90. | 
|  | Diag(LParenLoc, diag::ext_c99_compound_literal); | 
|  | ExprResult Result = ParseInitializer(); | 
|  | if (!Result.isInvalid() && Ty) | 
|  | return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.get()); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// ParseStringLiteralExpression - This handles the various token types that | 
|  | /// form string literals, and also handles string concatenation [C99 5.1.1.2, | 
|  | /// translation phase #6]. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///       primary-expression: [C99 6.5.1] | 
|  | ///         string-literal | 
|  | /// \verbatim | 
|  | ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { | 
|  | assert(isTokenStringLiteral() && "Not a string literal!"); | 
|  |  | 
|  | // String concat.  Note that keywords like __func__ and __FUNCTION__ are not | 
|  | // considered to be strings for concatenation purposes. | 
|  | SmallVector<Token, 4> StringToks; | 
|  |  | 
|  | do { | 
|  | StringToks.push_back(Tok); | 
|  | ConsumeStringToken(); | 
|  | } while (isTokenStringLiteral()); | 
|  |  | 
|  | // Pass the set of string tokens, ready for concatenation, to the actions. | 
|  | return Actions.ActOnStringLiteral(StringToks, | 
|  | AllowUserDefinedLiteral ? getCurScope() | 
|  | : nullptr); | 
|  | } | 
|  |  | 
|  | /// ParseGenericSelectionExpression - Parse a C11 generic-selection | 
|  | /// [C11 6.5.1.1]. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///    generic-selection: | 
|  | ///           _Generic ( assignment-expression , generic-assoc-list ) | 
|  | ///    generic-assoc-list: | 
|  | ///           generic-association | 
|  | ///           generic-assoc-list , generic-association | 
|  | ///    generic-association: | 
|  | ///           type-name : assignment-expression | 
|  | ///           default : assignment-expression | 
|  | /// \endverbatim | 
|  | ExprResult Parser::ParseGenericSelectionExpression() { | 
|  | assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); | 
|  | if (!getLangOpts().C11) | 
|  | Diag(Tok, diag::ext_c11_feature) << Tok.getName(); | 
|  |  | 
|  | SourceLocation KeyLoc = ConsumeToken(); | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren); | 
|  | if (T.expectAndConsume()) | 
|  | return ExprError(); | 
|  |  | 
|  | ExprResult ControllingExpr; | 
|  | { | 
|  | // C11 6.5.1.1p3 "The controlling expression of a generic selection is | 
|  | // not evaluated." | 
|  | EnterExpressionEvaluationContext Unevaluated( | 
|  | Actions, Sema::ExpressionEvaluationContext::Unevaluated); | 
|  | ControllingExpr = | 
|  | Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); | 
|  | if (ControllingExpr.isInvalid()) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ExpectAndConsume(tok::comma)) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | SourceLocation DefaultLoc; | 
|  | TypeVector Types; | 
|  | ExprVector Exprs; | 
|  | do { | 
|  | ParsedType Ty; | 
|  | if (Tok.is(tok::kw_default)) { | 
|  | // C11 6.5.1.1p2 "A generic selection shall have no more than one default | 
|  | // generic association." | 
|  | if (!DefaultLoc.isInvalid()) { | 
|  | Diag(Tok, diag::err_duplicate_default_assoc); | 
|  | Diag(DefaultLoc, diag::note_previous_default_assoc); | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  | DefaultLoc = ConsumeToken(); | 
|  | Ty = nullptr; | 
|  | } else { | 
|  | ColonProtectionRAIIObject X(*this); | 
|  | TypeResult TR = ParseTypeName(); | 
|  | if (TR.isInvalid()) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  | Ty = TR.get(); | 
|  | } | 
|  | Types.push_back(Ty); | 
|  |  | 
|  | if (ExpectAndConsume(tok::colon)) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | // FIXME: These expressions should be parsed in a potentially potentially | 
|  | // evaluated context. | 
|  | ExprResult ER( | 
|  | Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); | 
|  | if (ER.isInvalid()) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  | Exprs.push_back(ER.get()); | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  |  | 
|  | T.consumeClose(); | 
|  | if (T.getCloseLocation().isInvalid()) | 
|  | return ExprError(); | 
|  |  | 
|  | return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, | 
|  | T.getCloseLocation(), | 
|  | ControllingExpr.get(), | 
|  | Types, Exprs); | 
|  | } | 
|  |  | 
|  | /// Parse A C++1z fold-expression after the opening paren and optional | 
|  | /// left-hand-side expression. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///   fold-expression: | 
|  | ///       ( cast-expression fold-operator ... ) | 
|  | ///       ( ... fold-operator cast-expression ) | 
|  | ///       ( cast-expression fold-operator ... fold-operator cast-expression ) | 
|  | ExprResult Parser::ParseFoldExpression(ExprResult LHS, | 
|  | BalancedDelimiterTracker &T) { | 
|  | if (LHS.isInvalid()) { | 
|  | T.skipToEnd(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | tok::TokenKind Kind = tok::unknown; | 
|  | SourceLocation FirstOpLoc; | 
|  | if (LHS.isUsable()) { | 
|  | Kind = Tok.getKind(); | 
|  | assert(isFoldOperator(Kind) && "missing fold-operator"); | 
|  | FirstOpLoc = ConsumeToken(); | 
|  | } | 
|  |  | 
|  | assert(Tok.is(tok::ellipsis) && "not a fold-expression"); | 
|  | SourceLocation EllipsisLoc = ConsumeToken(); | 
|  |  | 
|  | ExprResult RHS; | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | if (!isFoldOperator(Tok.getKind())) | 
|  | return Diag(Tok.getLocation(), diag::err_expected_fold_operator); | 
|  |  | 
|  | if (Kind != tok::unknown && Tok.getKind() != Kind) | 
|  | Diag(Tok.getLocation(), diag::err_fold_operator_mismatch) | 
|  | << SourceRange(FirstOpLoc); | 
|  | Kind = Tok.getKind(); | 
|  | ConsumeToken(); | 
|  |  | 
|  | RHS = ParseExpression(); | 
|  | if (RHS.isInvalid()) { | 
|  | T.skipToEnd(); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | Diag(EllipsisLoc, getLangOpts().CPlusPlus17 | 
|  | ? diag::warn_cxx14_compat_fold_expression | 
|  | : diag::ext_fold_expression); | 
|  |  | 
|  | T.consumeClose(); | 
|  | return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind, | 
|  | EllipsisLoc, RHS.get(), T.getCloseLocation()); | 
|  | } | 
|  |  | 
|  | /// ParseExpressionList - Used for C/C++ (argument-)expression-list. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///       argument-expression-list: | 
|  | ///         assignment-expression | 
|  | ///         argument-expression-list , assignment-expression | 
|  | /// | 
|  | /// [C++] expression-list: | 
|  | /// [C++]   assignment-expression | 
|  | /// [C++]   expression-list , assignment-expression | 
|  | /// | 
|  | /// [C++0x] expression-list: | 
|  | /// [C++0x]   initializer-list | 
|  | /// | 
|  | /// [C++0x] initializer-list | 
|  | /// [C++0x]   initializer-clause ...[opt] | 
|  | /// [C++0x]   initializer-list , initializer-clause ...[opt] | 
|  | /// | 
|  | /// [C++0x] initializer-clause: | 
|  | /// [C++0x]   assignment-expression | 
|  | /// [C++0x]   braced-init-list | 
|  | /// \endverbatim | 
|  | bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, | 
|  | SmallVectorImpl<SourceLocation> &CommaLocs, | 
|  | llvm::function_ref<void()> ExpressionStarts) { | 
|  | bool SawError = false; | 
|  | while (1) { | 
|  | if (ExpressionStarts) | 
|  | ExpressionStarts(); | 
|  |  | 
|  | ExprResult Expr; | 
|  | if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { | 
|  | Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); | 
|  | Expr = ParseBraceInitializer(); | 
|  | } else | 
|  | Expr = ParseAssignmentExpression(); | 
|  |  | 
|  | if (Tok.is(tok::ellipsis)) | 
|  | Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); | 
|  | if (Expr.isInvalid()) { | 
|  | SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch); | 
|  | SawError = true; | 
|  | } else { | 
|  | Exprs.push_back(Expr.get()); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::comma)) | 
|  | break; | 
|  | // Move to the next argument, remember where the comma was. | 
|  | Token Comma = Tok; | 
|  | CommaLocs.push_back(ConsumeToken()); | 
|  |  | 
|  | checkPotentialAngleBracketDelimiter(Comma); | 
|  | } | 
|  | if (SawError) { | 
|  | // Ensure typos get diagnosed when errors were encountered while parsing the | 
|  | // expression list. | 
|  | for (auto &E : Exprs) { | 
|  | ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); | 
|  | if (Expr.isUsable()) E = Expr.get(); | 
|  | } | 
|  | } | 
|  | return SawError; | 
|  | } | 
|  |  | 
|  | /// ParseSimpleExpressionList - A simple comma-separated list of expressions, | 
|  | /// used for misc language extensions. | 
|  | /// | 
|  | /// \verbatim | 
|  | ///       simple-expression-list: | 
|  | ///         assignment-expression | 
|  | ///         simple-expression-list , assignment-expression | 
|  | /// \endverbatim | 
|  | bool | 
|  | Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, | 
|  | SmallVectorImpl<SourceLocation> &CommaLocs) { | 
|  | while (1) { | 
|  | ExprResult Expr = ParseAssignmentExpression(); | 
|  | if (Expr.isInvalid()) | 
|  | return true; | 
|  |  | 
|  | Exprs.push_back(Expr.get()); | 
|  |  | 
|  | if (Tok.isNot(tok::comma)) | 
|  | return false; | 
|  |  | 
|  | // Move to the next argument, remember where the comma was. | 
|  | Token Comma = Tok; | 
|  | CommaLocs.push_back(ConsumeToken()); | 
|  |  | 
|  | checkPotentialAngleBracketDelimiter(Comma); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). | 
|  | /// | 
|  | /// \verbatim | 
|  | /// [clang] block-id: | 
|  | /// [clang]   specifier-qualifier-list block-declarator | 
|  | /// \endverbatim | 
|  | void Parser::ParseBlockId(SourceLocation CaretLoc) { | 
|  | if (Tok.is(tok::code_completion)) { | 
|  | Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); | 
|  | return cutOffParsing(); | 
|  | } | 
|  |  | 
|  | // Parse the specifier-qualifier-list piece. | 
|  | DeclSpec DS(AttrFactory); | 
|  | ParseSpecifierQualifierList(DS); | 
|  |  | 
|  | // Parse the block-declarator. | 
|  | Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteralContext); | 
|  | DeclaratorInfo.setFunctionDefinitionKind(FDK_Definition); | 
|  | ParseDeclarator(DeclaratorInfo); | 
|  |  | 
|  | MaybeParseGNUAttributes(DeclaratorInfo); | 
|  |  | 
|  | // Inform sema that we are starting a block. | 
|  | Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); | 
|  | } | 
|  |  | 
|  | /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks | 
|  | /// like ^(int x){ return x+1; } | 
|  | /// | 
|  | /// \verbatim | 
|  | ///         block-literal: | 
|  | /// [clang]   '^' block-args[opt] compound-statement | 
|  | /// [clang]   '^' block-id compound-statement | 
|  | /// [clang] block-args: | 
|  | /// [clang]   '(' parameter-list ')' | 
|  | /// \endverbatim | 
|  | ExprResult Parser::ParseBlockLiteralExpression() { | 
|  | assert(Tok.is(tok::caret) && "block literal starts with ^"); | 
|  | SourceLocation CaretLoc = ConsumeToken(); | 
|  |  | 
|  | PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, | 
|  | "block literal parsing"); | 
|  |  | 
|  | // Enter a scope to hold everything within the block.  This includes the | 
|  | // argument decls, decls within the compound expression, etc.  This also | 
|  | // allows determining whether a variable reference inside the block is | 
|  | // within or outside of the block. | 
|  | ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | | 
|  | Scope::CompoundStmtScope | Scope::DeclScope); | 
|  |  | 
|  | // Inform sema that we are starting a block. | 
|  | Actions.ActOnBlockStart(CaretLoc, getCurScope()); | 
|  |  | 
|  | // Parse the return type if present. | 
|  | DeclSpec DS(AttrFactory); | 
|  | Declarator ParamInfo(DS, DeclaratorContext::BlockLiteralContext); | 
|  | ParamInfo.setFunctionDefinitionKind(FDK_Definition); | 
|  | // FIXME: Since the return type isn't actually parsed, it can't be used to | 
|  | // fill ParamInfo with an initial valid range, so do it manually. | 
|  | ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); | 
|  |  | 
|  | // If this block has arguments, parse them.  There is no ambiguity here with | 
|  | // the expression case, because the expression case requires a parameter list. | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | ParseParenDeclarator(ParamInfo); | 
|  | // Parse the pieces after the identifier as if we had "int(...)". | 
|  | // SetIdentifier sets the source range end, but in this case we're past | 
|  | // that location. | 
|  | SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); | 
|  | ParamInfo.SetIdentifier(nullptr, CaretLoc); | 
|  | ParamInfo.SetRangeEnd(Tmp); | 
|  | if (ParamInfo.isInvalidType()) { | 
|  | // If there was an error parsing the arguments, they may have | 
|  | // tried to use ^(x+y) which requires an argument list.  Just | 
|  | // skip the whole block literal. | 
|  | Actions.ActOnBlockError(CaretLoc, getCurScope()); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | MaybeParseGNUAttributes(ParamInfo); | 
|  |  | 
|  | // Inform sema that we are starting a block. | 
|  | Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); | 
|  | } else if (!Tok.is(tok::l_brace)) { | 
|  | ParseBlockId(CaretLoc); | 
|  | } else { | 
|  | // Otherwise, pretend we saw (void). | 
|  | SourceLocation NoLoc; | 
|  | ParamInfo.AddTypeInfo( | 
|  | DeclaratorChunk::getFunction(/*HasProto=*/true, | 
|  | /*IsAmbiguous=*/false, | 
|  | /*RParenLoc=*/NoLoc, | 
|  | /*ArgInfo=*/nullptr, | 
|  | /*NumParams=*/0, | 
|  | /*EllipsisLoc=*/NoLoc, | 
|  | /*RParenLoc=*/NoLoc, | 
|  | /*RefQualifierIsLvalueRef=*/true, | 
|  | /*RefQualifierLoc=*/NoLoc, | 
|  | /*MutableLoc=*/NoLoc, EST_None, | 
|  | /*ESpecRange=*/SourceRange(), | 
|  | /*Exceptions=*/nullptr, | 
|  | /*ExceptionRanges=*/nullptr, | 
|  | /*NumExceptions=*/0, | 
|  | /*NoexceptExpr=*/nullptr, | 
|  | /*ExceptionSpecTokens=*/nullptr, | 
|  | /*DeclsInPrototype=*/None, CaretLoc, | 
|  | CaretLoc, ParamInfo), | 
|  | CaretLoc); | 
|  |  | 
|  | MaybeParseGNUAttributes(ParamInfo); | 
|  |  | 
|  | // Inform sema that we are starting a block. | 
|  | Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); | 
|  | } | 
|  |  | 
|  |  | 
|  | ExprResult Result(true); | 
|  | if (!Tok.is(tok::l_brace)) { | 
|  | // Saw something like: ^expr | 
|  | Diag(Tok, diag::err_expected_expression); | 
|  | Actions.ActOnBlockError(CaretLoc, getCurScope()); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | StmtResult Stmt(ParseCompoundStatementBody()); | 
|  | BlockScope.Exit(); | 
|  | if (!Stmt.isInvalid()) | 
|  | Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope()); | 
|  | else | 
|  | Actions.ActOnBlockError(CaretLoc, getCurScope()); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. | 
|  | /// | 
|  | ///         '__objc_yes' | 
|  | ///         '__objc_no' | 
|  | ExprResult Parser::ParseObjCBoolLiteral() { | 
|  | tok::TokenKind Kind = Tok.getKind(); | 
|  | return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); | 
|  | } | 
|  |  | 
|  | /// Validate availability spec list, emitting diagnostics if necessary. Returns | 
|  | /// true if invalid. | 
|  | static bool CheckAvailabilitySpecList(Parser &P, | 
|  | ArrayRef<AvailabilitySpec> AvailSpecs) { | 
|  | llvm::SmallSet<StringRef, 4> Platforms; | 
|  | bool HasOtherPlatformSpec = false; | 
|  | bool Valid = true; | 
|  | for (const auto &Spec : AvailSpecs) { | 
|  | if (Spec.isOtherPlatformSpec()) { | 
|  | if (HasOtherPlatformSpec) { | 
|  | P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_star); | 
|  | Valid = false; | 
|  | } | 
|  |  | 
|  | HasOtherPlatformSpec = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | bool Inserted = Platforms.insert(Spec.getPlatform()).second; | 
|  | if (!Inserted) { | 
|  | // Rule out multiple version specs referring to the same platform. | 
|  | // For example, we emit an error for: | 
|  | // @available(macos 10.10, macos 10.11, *) | 
|  | StringRef Platform = Spec.getPlatform(); | 
|  | P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_platform) | 
|  | << Spec.getEndLoc() << Platform; | 
|  | Valid = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!HasOtherPlatformSpec) { | 
|  | SourceLocation InsertWildcardLoc = AvailSpecs.back().getEndLoc(); | 
|  | P.Diag(InsertWildcardLoc, diag::err_availability_query_wildcard_required) | 
|  | << FixItHint::CreateInsertion(InsertWildcardLoc, ", *"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return !Valid; | 
|  | } | 
|  |  | 
|  | /// Parse availability query specification. | 
|  | /// | 
|  | ///  availability-spec: | 
|  | ///     '*' | 
|  | ///     identifier version-tuple | 
|  | Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() { | 
|  | if (Tok.is(tok::star)) { | 
|  | return AvailabilitySpec(ConsumeToken()); | 
|  | } else { | 
|  | // Parse the platform name. | 
|  | if (Tok.is(tok::code_completion)) { | 
|  | Actions.CodeCompleteAvailabilityPlatformName(); | 
|  | cutOffParsing(); | 
|  | return None; | 
|  | } | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | Diag(Tok, diag::err_avail_query_expected_platform_name); | 
|  | return None; | 
|  | } | 
|  |  | 
|  | IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc(); | 
|  | SourceRange VersionRange; | 
|  | VersionTuple Version = ParseVersionTuple(VersionRange); | 
|  |  | 
|  | if (Version.empty()) | 
|  | return None; | 
|  |  | 
|  | StringRef GivenPlatform = PlatformIdentifier->Ident->getName(); | 
|  | StringRef Platform = | 
|  | AvailabilityAttr::canonicalizePlatformName(GivenPlatform); | 
|  |  | 
|  | if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) { | 
|  | Diag(PlatformIdentifier->Loc, | 
|  | diag::err_avail_query_unrecognized_platform_name) | 
|  | << GivenPlatform; | 
|  | return None; | 
|  | } | 
|  |  | 
|  | return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc, | 
|  | VersionRange.getEnd()); | 
|  | } | 
|  | } | 
|  |  | 
|  | ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) { | 
|  | assert(Tok.is(tok::kw___builtin_available) || | 
|  | Tok.isObjCAtKeyword(tok::objc_available)); | 
|  |  | 
|  | // Eat the available or __builtin_available. | 
|  | ConsumeToken(); | 
|  |  | 
|  | BalancedDelimiterTracker Parens(*this, tok::l_paren); | 
|  | if (Parens.expectAndConsume()) | 
|  | return ExprError(); | 
|  |  | 
|  | SmallVector<AvailabilitySpec, 4> AvailSpecs; | 
|  | bool HasError = false; | 
|  | while (true) { | 
|  | Optional<AvailabilitySpec> Spec = ParseAvailabilitySpec(); | 
|  | if (!Spec) | 
|  | HasError = true; | 
|  | else | 
|  | AvailSpecs.push_back(*Spec); | 
|  |  | 
|  | if (!TryConsumeToken(tok::comma)) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (HasError) { | 
|  | SkipUntil(tok::r_paren, StopAtSemi); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | CheckAvailabilitySpecList(*this, AvailSpecs); | 
|  |  | 
|  | if (Parens.consumeClose()) | 
|  | return ExprError(); | 
|  |  | 
|  | return Actions.ActOnObjCAvailabilityCheckExpr(AvailSpecs, BeginLoc, | 
|  | Parens.getCloseLocation()); | 
|  | } |