text: //===--- 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
  ///         = *= /= %= += -= <<= >>= &= ^= |= [= _Cilk_spawn]
  ///
  ///       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::Unevaluated);
    ExprResult LHS(ParseCastExpression(AnyCastExpr));
    ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
    if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
      Actions.CorrectDelayedTyposInExpr(Res);
      return ExprError();
    }
    return Res;
  }
  
  /// \brief Parse a constraint-logical-and-expression.
  ///
  /// \verbatim
  ///       C++2a[temp.constr.decl]p1
  ///       constraint-logical-and-expression:
  ///         primary-expression
  ///         constraint-logical-and-expression '&&' primary-expression
  ///
  /// \endverbatim
  ExprResult
  Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
    EnterExpressionEvaluationContext ConstantEvaluated(
        Actions, Sema::ExpressionEvaluationContext::Unevaluated);
    bool NotPrimaryExpression = false;
    auto ParsePrimary = [&] () {
      ExprResult E = ParseCastExpression(PrimaryExprOnly,
                                         /*isAddressOfOperand=*/false,
                                         /*isTypeCast=*/NotTypeCast,
                                         /*isVectorLiteral=*/false,
                                         &NotPrimaryExpression);
      if (E.isInvalid())
        return ExprError();
      auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) {
          E = ParsePostfixExpressionSuffix(E);
          // Use InclusiveOr, the precedence just after '&&' to not parse the
          // next arguments to the logical and.
          E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr);
          if (!E.isInvalid())
            Diag(E.get()->getExprLoc(),
                 Note
                 ? diag::note_unparenthesized_non_primary_expr_in_requires_clause
                 : diag::err_unparenthesized_non_primary_expr_in_requires_clause)
                 << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(")
                 << FixItHint::CreateInsertion(
                     PP.getLocForEndOfToken(E.get()->getEndLoc()), ")")
                 << E.get()->getSourceRange();
          return E;
      };
  
      if (NotPrimaryExpression ||
          // Check if the following tokens must be a part of a non-primary
          // expression
          getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
                             /*CPlusPlus11=*/true) > prec::LogicalAnd ||
          // Postfix operators other than '(' (which will be checked for in
          // CheckConstraintExpression).
          Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) ||
          (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) {
        E = RecoverFromNonPrimary(E, /*Note=*/false);
        if (E.isInvalid())
          return ExprError();
        NotPrimaryExpression = false;
      }
      bool PossibleNonPrimary;
      bool IsConstraintExpr =
          Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary,
                                            IsTrailingRequiresClause);
      if (!IsConstraintExpr || PossibleNonPrimary) {
        // Atomic constraint might be an unparenthesized non-primary expression
        // (such as a binary operator), in which case we might get here (e.g. in
        // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore
        // the rest of the addition expression). Try to parse the rest of it here.
        if (PossibleNonPrimary)
          E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr);
        Actions.CorrectDelayedTyposInExpr(E);
        return ExprError();
      }
      return E;
    };
    ExprResult LHS = ParsePrimary();
    if (LHS.isInvalid())
      return ExprError();
    while (Tok.is(tok::ampamp)) {
      SourceLocation LogicalAndLoc = ConsumeToken();
      ExprResult RHS = ParsePrimary();
      if (RHS.isInvalid()) {
        Actions.CorrectDelayedTyposInExpr(LHS);
        return ExprError();
      }
      ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc,
                                         tok::ampamp, LHS.get(), RHS.get());
      if (!Op.isUsable()) {
        Actions.CorrectDelayedTyposInExpr(RHS);
        Actions.CorrectDelayedTyposInExpr(LHS);
        return ExprError();
      }
      LHS = Op;
    }
    return LHS;
  }
  
  /// \brief Parse a constraint-logical-or-expression.
  ///
  /// \verbatim
  ///       C++2a[temp.constr.decl]p1
  ///       constraint-logical-or-expression:
  ///         constraint-logical-and-expression
  ///         constraint-logical-or-expression '||'
  ///             constraint-logical-and-expression
  ///
  /// \endverbatim
  ExprResult
  Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) {
    ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause));
    if (!LHS.isUsable())
      return ExprError();
    while (Tok.is(tok::pipepipe)) {
      SourceLocation LogicalOrLoc = ConsumeToken();
      ExprResult RHS =
          ParseConstraintLogicalAndExpression(IsTrailingRequiresClause);
      if (!RHS.isUsable()) {
        Actions.CorrectDelayedTyposInExpr(LHS);
        return ExprError();
      }
      ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc,
                                         tok::pipepipe, LHS.get(), RHS.get());
      if (!Op.isUsable()) {
        Actions.CorrectDelayedTyposInExpr(RHS);
        Actions.CorrectDelayedTyposInExpr(LHS);
        return ExprError();
      }
      LHS = Op;
    }
    return LHS;
  }
  
  bool Parser::isNotExpressionStart() {
    tok::TokenKind K = Tok.getKind();
    if (K == tok::l_brace || K == tok::r_brace  ||
        K == tok::kw_for  || K == tok::kw_while ||
        K == tok::kw_if   || K == tok::kw_else  ||
        K == tok::kw_goto || K == tok::kw_try)
      return true;
    // If this is a decl-specifier, we can't be at the start of an expression.
    return isKnownToBeDeclarationSpecifier();
  }
  
  bool Parser::isFoldOperator(prec::Level Level) const {
    return Level > prec::Unknown && Level != prec::Conditional &&
           Level != prec::Spaceship;
  }
  
  bool Parser::isFoldOperator(tok::TokenKind Kind) const {
    return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true));
  }
  
  /// Parse a binary expression that starts with \p LHS and has a
  /// precedence of at least \p MinPrec.
  ExprResult
  Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
    prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
                                                 GreaterThanIsOperator,
                                                 getLangOpts().CPlusPlus11);
    SourceLocation ColonLoc;
  
    auto SavedType = PreferredType;
    while (1) {
      // Every iteration may rely on a preferred type for the whole expression.
      PreferredType = SavedType;
      // If this token has a lower precedence than we are allowed to parse (e.g.
      // because we are called recursively, or because the token is not a binop),
      // then we are done!
      if (NextTokPrec < MinPrec)
        return LHS;
  
      // Consume the operator, saving the operator token for error reporting.
      Token OpToken = Tok;
      ConsumeToken();
  
      if (OpToken.is(tok::caretcaret)) {
        return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or));
      }
  
      // If we're potentially in a template-id, we may now be able to determine
      // whether we're actually in one or not.
      if (OpToken.isOneOf(tok::comma, tok::greater, tok::greatergreater,
                          tok::greatergreatergreater) &&
          checkPotentialAngleBracketDelimiter(OpToken))
        return ExprError();
  
      // Bail out when encountering a comma followed by a token which can't
      // possibly be the start of an expression. For instance:
      //   int f() { return 1, }
      // We can't do this before consuming the comma, because
      // isNotExpressionStart() looks at the token stream.
      if (OpToken.is(tok::comma) && isNotExpressionStart()) {
        PP.EnterToken(Tok, /*IsReinject*/true);
        Tok = OpToken;
        return LHS;
      }
  
      // If the next token is an ellipsis, then this is a fold-expression. Leave
      // it alone so we can handle it in the paren expression.
      if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
        // FIXME: We can't check this via lookahead before we consume the token
        // because that tickles a lexer bug.
        PP.EnterToken(Tok, /*IsReinject*/true);
        Tok = OpToken;
        return LHS;
      }
  
      // In Objective-C++, alternative operator tokens can be used as keyword args
      // in message expressions. Unconsume the token so that it can reinterpreted
      // as an identifier in ParseObjCMessageExpressionBody. i.e., we support:
      //   [foo meth:0 and:0];
      //   [foo not_eq];
      if (getLangOpts().ObjC && getLangOpts().CPlusPlus &&
          Tok.isOneOf(tok::colon, tok::r_square) &&
          OpToken.getIdentifierInfo() != nullptr) {
        PP.EnterToken(Tok, /*IsReinject*/true);
        Tok = OpToken;
        return LHS;
      }
  
      // Special case handling for the ternary operator.
      ExprResult TernaryMiddle(true);
      if (NextTokPrec == prec::Conditional) {
        if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
          // Parse a braced-init-list here for error recovery purposes.
          SourceLocation BraceLoc = Tok.getLocation();
          TernaryMiddle = ParseBraceInitializer();
          if (!TernaryMiddle.isInvalid()) {
            Diag(BraceLoc, diag::err_init_list_bin_op)
                << /*RHS*/ 1 << PP.getSpelling(OpToken)
                << Actions.getExprRange(TernaryMiddle.get());
            TernaryMiddle = ExprError();
          }
        } else if (Tok.isNot(tok::colon)) {
          // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
          ColonProtectionRAIIObject X(*this);
  
          // Handle this production specially:
          //   logical-OR-expression '?' expression ':' conditional-expression
          // In particular, the RHS of the '?' is 'expression', not
          // 'logical-OR-expression' as we might expect.
          TernaryMiddle = ParseExpression();
        } else {
          // Special case handling of "X ? Y : Z" where Y is empty:
          //   logical-OR-expression '?' ':' conditional-expression   [GNU]
          TernaryMiddle = nullptr;
          Diag(Tok, diag::ext_gnu_conditional_expr);
        }
  
        if (TernaryMiddle.isInvalid()) {
          Actions.CorrectDelayedTyposInExpr(LHS);
          LHS = ExprError();
          TernaryMiddle = nullptr;
        }
  
        if (!TryConsumeToken(tok::colon, ColonLoc)) {
          // Otherwise, we're missing a ':'.  Assume that this was a typo that
          // the user forgot. If we're not in a macro expansion, we can suggest
          // a fixit hint. If there were two spaces before the current token,
          // suggest inserting the colon in between them, otherwise insert ": ".
          SourceLocation FILoc = Tok.getLocation();
          const char *FIText = ": ";
          const SourceManager &SM = PP.getSourceManager();
          if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) {
            assert(FILoc.isFileID());
            bool IsInvalid = false;
            const char *SourcePtr =
              SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid);
            if (!IsInvalid && *SourcePtr == ' ') {
              SourcePtr =
                SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid);
              if (!IsInvalid && *SourcePtr == ' ') {
                FILoc = FILoc.getLocWithOffset(-1);
                FIText = ":";
              }
            }
          }
  
          Diag(Tok, diag::err_expected)
              << tok::colon << FixItHint::CreateInsertion(FILoc, FIText);
          Diag(OpToken, diag::note_matching) << tok::question;
          ColonLoc = Tok.getLocation();
        }
      }
  
      PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(),
                                OpToken.getKind());
      // Parse another leaf here for the RHS of the operator.
      // ParseCastExpression works here because all RHS expressions in C have it
      // as a prefix, at least. However, in C++, an assignment-expression could
      // be a throw-expression, which is not a valid cast-expression.
      // Therefore we need some special-casing here.
      // Also note that the third operand of the conditional operator is
      // an assignment-expression in C++, and in C++11, we can have a
      // braced-init-list on the RHS of an assignment. For better diagnostics,
      // parse as if we were allowed braced-init-lists everywhere, and check that
      // they only appear on the RHS of assignments later.
      ExprResult RHS;
      bool RHSIsInitList = false;
      if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
        RHS = ParseBraceInitializer();
        RHSIsInitList = true;
      } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
        RHS = ParseAssignmentExpression();
      else
        RHS = ParseCastExpression(AnyCastExpr);
  
      if (RHS.isInvalid()) {
        // FIXME: Errors generated by the delayed typo correction should be
        // printed before errors from parsing the RHS, not after.
        Actions.CorrectDelayedTyposInExpr(LHS);
        if (TernaryMiddle.isUsable())
          TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
        LHS = ExprError();
      }
  
      // Remember the precedence of this operator and get the precedence of the
      // operator immediately to the right of the RHS.
      prec::Level ThisPrec = NextTokPrec;
      NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
                                       getLangOpts().CPlusPlus11);
  
      // Assignment and conditional expressions are right-associative.
      bool isRightAssoc = ThisPrec == prec::Conditional ||
                          ThisPrec == prec::Assignment;
  
      // Get the precedence of the operator to the right of the RHS.  If it binds
      // more tightly with RHS than we do, evaluate it completely first.
      if (ThisPrec < NextTokPrec ||
          (ThisPrec == NextTokPrec && isRightAssoc)) {
        if (!RHS.isInvalid() && RHSIsInitList) {
          Diag(Tok, diag::err_init_list_bin_op)
            << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get());
          RHS = ExprError();
        }
        // If this is left-associative, only parse things on the RHS that bind
        // more tightly than the current operator.  If it is left-associative, it
        // is okay, to bind exactly as tightly.  For example, compile A=B=C=D as
        // A=(B=(C=D)), where each paren is a level of recursion here.
        // The function takes ownership of the RHS.
        RHS = ParseRHSOfBinaryExpression(RHS,
                              static_cast<prec::Level>(ThisPrec + !isRightAssoc));
        RHSIsInitList = false;
  
        if (RHS.isInvalid()) {
          // FIXME: Errors generated by the delayed typo correction should be
          // printed before errors from ParseRHSOfBinaryExpression, not after.
          Actions.CorrectDelayedTyposInExpr(LHS);
          if (TernaryMiddle.isUsable())
            TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
          LHS = ExprError();
        }
  
        NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
                                         getLangOpts().CPlusPlus11);
      }
  
      if (!RHS.isInvalid() && RHSIsInitList) {
        if (ThisPrec == prec::Assignment) {
          Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists)
            << Actions.getExprRange(RHS.get());
        } else if (ColonLoc.isValid()) {
          Diag(ColonLoc, diag::err_init_list_bin_op)
            << /*RHS*/1 << ":"
            << Actions.getExprRange(RHS.get());
          LHS = ExprError();
        } else {
          Diag(OpToken, diag::err_init_list_bin_op)
            << /*RHS*/1 << PP.getSpelling(OpToken)
            << Actions.getExprRange(RHS.get());
          LHS = ExprError();
        }
      }
  
      ExprResult OrigLHS = LHS;
      if (!LHS.isInvalid()) {
        // Combine the LHS and RHS into the LHS (e.g. build AST).
        if (TernaryMiddle.isInvalid()) {
          // If we're using '>>' as an operator within a template
          // argument list (in C++98), suggest the addition of
          // parentheses so that the code remains well-formed in C++0x.
          if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
            SuggestParentheses(OpToken.getLocation(),
                               diag::warn_cxx11_right_shift_in_template_arg,
                           SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
                                       Actions.getExprRange(RHS.get()).getEnd()));
  
          ExprResult BinOp =
              Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(),
                                 OpToken.getKind(), LHS.get(), RHS.get());
          if (BinOp.isInvalid())
            BinOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(),
                                               RHS.get()->getEndLoc(),
                                               {LHS.get(), RHS.get()});
  
          LHS = BinOp;
        } else {
          ExprResult CondOp = Actions.ActOnConditionalOp(
              OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(),
              RHS.get());
          if (CondOp.isInvalid()) {
            std::vector<clang::Expr *> Args;
            // TernaryMiddle can be null for the GNU conditional expr extension.
            if (TernaryMiddle.get())
              Args = {LHS.get(), TernaryMiddle.get(), RHS.get()};
            else
              Args = {LHS.get(), RHS.get()};
            CondOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(),
                                                RHS.get()->getEndLoc(), Args);
          }
  
          LHS = CondOp;
        }
        // In this case, ActOnBinOp or ActOnConditionalOp performed the
        // CorrectDelayedTyposInExpr check.
        if (!getLangOpts().CPlusPlus)
          continue;
      }
  
      // Ensure potential typos aren't left undiagnosed.
      if (LHS.isInvalid()) {
        Actions.CorrectDelayedTyposInExpr(OrigLHS);
        Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
        Actions.CorrectDelayedTyposInExpr(RHS);
      }
    }
  }
  
  /// Parse a cast-expression, unary-expression or primary-expression, based
  /// on \p ExprType.
  ///
  /// \p isAddressOfOperand exists because an id-expression that is the
  /// operand of address-of gets special treatment due to member pointers.
  ///
  ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
                                         bool isAddressOfOperand,
                                         TypeCastState isTypeCast,
                                         bool isVectorLiteral,
                                         bool *NotPrimaryExpression) {
    bool NotCastExpr;
    ExprResult Res = ParseCastExpression(ParseKind,
                                         isAddressOfOperand,
                                         NotCastExpr,
                                         isTypeCast,
                                         isVectorLiteral,
                                         NotPrimaryExpression);
    if (NotCastExpr)
      Diag(Tok, diag::err_expected_expression);
    return Res;
  }
  
  namespace {
  class CastExpressionIdValidator final : public CorrectionCandidateCallback {
   public:
    CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes)
        : NextToken(Next), AllowNonTypes(AllowNonTypes) {
      WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes;
    }
  
    bool ValidateCandidate(const TypoCorrection &candidate) override {
      NamedDecl *ND = candidate.getCorrectionDecl();
      if (!ND)
        return candidate.isKeyword();
  
      if (isa<TypeDecl>(ND))
        return WantTypeSpecifiers;
  
      if (!AllowNonTypes || !CorrectionCandidateCallback::ValidateCandidate(candidate))
        return false;
  
      if (!NextToken.isOneOf(tok::equal, tok::arrow, tok::period))
        return true;
  
      for (auto *C : candidate) {
        NamedDecl *ND = C->getUnderlyingDecl();
        if (isa<ValueDecl>(ND) && !isa<FunctionDecl>(ND))
          return true;
      }
      return false;
    }
  
    std::unique_ptr<CorrectionCandidateCallback> clone() override {
      return std::make_unique<CastExpressionIdValidator>(*this);
    }
  
   private:
    Token NextToken;
    bool AllowNonTypes;
  };
  }
  
  /// Parse a cast-expression, or, if \pisUnaryExpression is true, parse
  /// a unary-expression.
  ///
  /// \p isAddressOfOperand exists because an id-expression that is the operand
  /// of address-of gets special treatment due to member pointers. NotCastExpr
  /// is set to true if the token is not the start of a cast-expression, and no
  /// diagnostic is emitted in this case and no tokens are consumed.
  ///
  /// \verbatim
  ///       cast-expression: [C99 6.5.4]
  ///         unary-expression
  ///         '(' type-name ')' cast-expression
  ///
  ///       unary-expression:  [C99 6.5.3]
  ///         postfix-expression
  ///         '++' unary-expression
  ///         '--' unary-expression
  /// [Coro]  'co_await' cast-expression
  ///         unary-operator cast-expression
  ///         'sizeof' unary-expression
  ///         'sizeof' '(' type-name ')'
  /// [C++11] 'sizeof' '...' '(' identifier ')'
  /// [GNU]   '__alignof' unary-expression
  /// [GNU]   '__alignof' '(' type-name ')'
  /// [C11]   '_Alignof' '(' type-name ')'
  /// [C++11] 'alignof' '(' type-id ')'
  /// [GNU]   '&&' identifier
  /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7]
  /// [C++]   new-expression
  /// [C++]   delete-expression
  ///
  ///       unary-operator: one of
  ///         '&'  '*'  '+'  '-'  '~'  '!'
  /// [GNU]   '__extension__'  '__real'  '__imag'
  ///
  ///       primary-expression: [C99 6.5.1]
  /// [C99]   identifier
  /// [C++]   id-expression
  ///         constant
  ///         string-literal
  /// [C++]   boolean-literal  [C++ 2.13.5]
  /// [C++11] 'nullptr'        [C++11 2.14.7]
  /// [C++11] user-defined-literal
  ///         '(' expression ')'
  /// [C11]   generic-selection
  /// [C++2a] requires-expression
  ///         '__func__'        [C99 6.4.2.2]
  /// [GNU]   '__FUNCTION__'
  /// [MS]    '__FUNCDNAME__'
  /// [MS]    'L__FUNCTION__'
  /// [MS]    '__FUNCSIG__'
  /// [MS]    'L__FUNCSIG__'
  /// [GNU]   '__PRETTY_FUNCTION__'
  /// [GNU]   '(' compound-statement ')'
  /// [GNU]   '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
  /// [GNU]   '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
  /// [GNU]   '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
  ///                                     assign-expr ')'
  /// [GNU]   '__builtin_FILE' '(' ')'
  /// [GNU]   '__builtin_FUNCTION' '(' ')'
  /// [GNU]   '__builtin_LINE' '(' ')'
  /// [CLANG] '__builtin_COLUMN' '(' ')'
  /// [GNU]   '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
  /// [GNU]   '__null'
  /// [OBJC]  '[' objc-message-expr ']'
  /// [OBJC]  '\@selector' '(' objc-selector-arg ')'
  /// [OBJC]  '\@protocol' '(' identifier ')'
  /// [OBJC]  '\@encode' '(' type-name ')'
  /// [OBJC]  objc-string-literal
  /// [C++]   simple-type-specifier '(' expression-list[opt] ')'      [C++ 5.2.3]
  /// [C++11] simple-type-specifier braced-init-list                  [C++11 5.2.3]
  /// [C++]   typename-specifier '(' expression-list[opt] ')'         [C++ 5.2.3]
  /// [C++11] typename-specifier braced-init-list                     [C++11 5.2.3]
  /// [C++]   'const_cast' '<' type-name '>' '(' expression ')'       [C++ 5.2p1]
  /// [C++]   'dynamic_cast' '<' type-name '>' '(' expression ')'     [C++ 5.2p1]
  /// [C++]   'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
  /// [C++]   'static_cast' '<' type-name '>' '(' expression ')'      [C++ 5.2p1]
  /// [C++]   'typeid' '(' expression ')'                             [C++ 5.2p1]
  /// [C++]   'typeid' '(' type-id ')'                                [C++ 5.2p1]
  /// [C++]   'this'          [C++ 9.3.2]
  /// [G++]   unary-type-trait '(' type-id ')'
  /// [G++]   binary-type-trait '(' type-id ',' type-id ')'           [TODO]
  /// [EMBT]  array-type-trait '(' type-id ',' integer ')'
  /// [clang] '^' block-literal
  ///
  ///       constant: [C99 6.4.4]
  ///         integer-constant
  ///         floating-constant
  ///         enumeration-constant -> identifier
  ///         character-constant
  ///
  ///       id-expression: [C++ 5.1]
  ///                   unqualified-id
  ///                   qualified-id
  ///
  ///       unqualified-id: [C++ 5.1]
  ///                   identifier
  ///                   operator-function-id
  ///                   conversion-function-id
  ///                   '~' class-name
  ///                   template-id
  ///
  ///       new-expression: [C++ 5.3.4]
  ///                   '::'[opt] 'new' new-placement[opt] new-type-id
  ///                                     new-initializer[opt]
  ///                   '::'[opt] 'new' new-placement[opt] '(' type-id ')'
  ///                                     new-initializer[opt]
  ///
  ///       delete-expression: [C++ 5.3.5]
  ///                   '::'[opt] 'delete' cast-expression
  ///                   '::'[opt] 'delete' '[' ']' cast-expression
  ///
  /// [GNU/Embarcadero] unary-type-trait:
  ///                   '__is_arithmetic'
  ///                   '__is_floating_point'
  ///                   '__is_integral'
  ///                   '__is_lvalue_expr'
  ///                   '__is_rvalue_expr'
  ///                   '__is_complete_type'
  ///                   '__is_void'
  ///                   '__is_array'
  ///                   '__is_function'
  ///                   '__is_reference'
  ///                   '__is_lvalue_reference'
  ///                   '__is_rvalue_reference'
  ///                   '__is_fundamental'
  ///                   '__is_object'
  ///                   '__is_scalar'
  ///                   '__is_compound'
  ///                   '__is_pointer'
  ///                   '__is_member_object_pointer'
  ///                   '__is_member_function_pointer'
  ///                   '__is_member_pointer'
  ///                   '__is_const'
  ///                   '__is_volatile'
  ///                   '__is_trivial'
  ///                   '__is_standard_layout'
  ///                   '__is_signed'
  ///                   '__is_unsigned'
  ///
  /// [GNU] unary-type-trait:
  ///                   '__has_nothrow_assign'
  ///                   '__has_nothrow_copy'
  ///                   '__has_nothrow_constructor'
  ///                   '__has_trivial_assign'                  [TODO]
  ///                   '__has_trivial_copy'                    [TODO]
  ///                   '__has_trivial_constructor'
  ///                   '__has_trivial_destructor'
  ///                   '__has_virtual_destructor'
  ///                   '__is_abstract'                         [TODO]
  ///                   '__is_class'
  ///                   '__is_empty'                            [TODO]
  ///                   '__is_enum'
  ///                   '__is_final'
  ///                   '__is_pod'
  ///                   '__is_polymorphic'
  ///                   '__is_sealed'                           [MS]
  ///                   '__is_trivial'
  ///                   '__is_union'
  ///                   '__has_unique_object_representations'
  ///
  /// [Clang] unary-type-trait:
  ///                   '__is_aggregate'
  ///                   '__trivially_copyable'
  ///
  ///       binary-type-trait:
  /// [GNU]             '__is_base_of'
  /// [MS]              '__is_convertible_to'
  ///                   '__is_convertible'
  ///                   '__is_same'
  ///
  /// [Embarcadero] array-type-trait:
  ///                   '__array_rank'
  ///                   '__array_extent'
  ///
  /// [Embarcadero] expression-trait:
  ///                   '__is_lvalue_expr'
  ///                   '__is_rvalue_expr'
  /// \endverbatim
  ///
  ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
                                         bool isAddressOfOperand,
                                         bool &NotCastExpr,
                                         TypeCastState isTypeCast,
                                         bool isVectorLiteral,
                                         bool *NotPrimaryExpression) {
    ExprResult Res;
    tok::TokenKind SavedKind = Tok.getKind();
    auto SavedType = PreferredType;
    NotCastExpr = false;
  
    // Are postfix-expression suffix operators permitted after this
    // cast-expression? If not, and we find some, we'll parse them anyway and
    // diagnose them.
    bool AllowSuffix = true;
  
    // This handles all of cast-expression, unary-expression, postfix-expression,
    // and primary-expression.  We handle them together like this for efficiency
    // and to simplify handling of an expression starting with a '(' token: which
    // may be one of a parenthesized expression, cast-expression, compound literal
    // expression, or statement expression.
    //
    // If the parsed tokens consist of a primary-expression, the cases below
    // break out of the switch;  at the end we call ParsePostfixExpressionSuffix
    // to handle the postfix expression suffixes.  Cases that cannot be followed
    // by postfix exprs should set AllowSuffix to false.
    switch (SavedKind) {
    case tok::l_paren: {
      // If this expression is limited to being a unary-expression, the paren can
      // not start a cast expression.
      ParenParseOption ParenExprType;
      switch (ParseKind) {
        case CastParseKind::UnaryExprOnly:
          if (!getLangOpts().CPlusPlus)
            ParenExprType = CompoundLiteral;
          LLVM_FALLTHROUGH;
        case CastParseKind::AnyCastExpr:
          ParenExprType = ParenParseOption::CastExpr;
          break;
        case CastParseKind::PrimaryExprOnly:
          ParenExprType = FoldExpr;
          break;
      }
      ParsedType CastTy;
      SourceLocation RParenLoc;
      Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
                                 isTypeCast == IsTypeCast, CastTy, RParenLoc);
  
      // FIXME: What should we do if a vector literal is followed by a
      // postfix-expression suffix? Usually postfix operators are permitted on
      // literals.
      if (isVectorLiteral)
        return Res;
  
      switch (ParenExprType) {
      case SimpleExpr:   break;    // Nothing else to do.
      case CompoundStmt: break;  // Nothing else to do.
      case CompoundLiteral:
        // We parsed '(' type-name ')' '{' ... '}'.  If any suffixes of
        // postfix-expression exist, parse them now.
        break;
      case CastExpr:
        // We have parsed the cast-expression and no postfix-expr pieces are
        // following.
        return Res;
      case FoldExpr:
        // We only parsed a fold-expression. There might be postfix-expr pieces
        // afterwards; parse them now.
        break;
      }
  
      break;
    }
  
      // primary-expression
    case tok::numeric_constant:
      // constant: integer-constant
      // constant: floating-constant
  
      Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope());
      ConsumeToken();
      break;
  
    case tok::kw_true:
    case tok::kw_false:
      Res = ParseCXXBoolLiteral();
      break;
  
    case tok::kw___objc_yes:
    case tok::kw___objc_no:
      Res = ParseObjCBoolLiteral();
      break;
  
    case tok::kw_nullptr:
      Diag(Tok, diag::warn_cxx98_compat_nullptr);
      Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
      break;
  
    case tok::annot_primary_expr:
    case tok::annot_overload_set:
      Res = getExprAnnotation(Tok);
      if (!Res.isInvalid() && Tok.getKind() == tok::annot_overload_set)
        Res = Actions.ActOnNameClassifiedAsOverloadSet(getCurScope(), Res.get());
      ConsumeAnnotationToken();
      if (!Res.isInvalid() && Tok.is(tok::less))
        checkPotentialAngleBracket(Res);
      break;
  
    case tok::annot_non_type:
    case tok::annot_non_type_dependent:
    case tok::annot_non_type_undeclared: {
      CXXScopeSpec SS;
      Token Replacement;
      Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
      assert(!Res.isUnset() &&
             "should not perform typo correction on annotation token");
      break;
    }
  
    case tok::kw___super:
    case tok::kw_decltype:
      // Annotate the token and tail recurse.
      if (TryAnnotateTypeOrScopeToken())
        return ExprError();
      assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
      return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
                                 isVectorLiteral, NotPrimaryExpression);
  
    case tok::identifier: {      // primary-expression: identifier
                                 // unqualified-id: identifier
                                 // constant: enumeration-constant
      // Turn a potentially qualified name into a annot_typename or
      // annot_cxxscope if it would be valid.  This handles things like x::y, etc.
      if (getLangOpts().CPlusPlus) {
        // Avoid the unnecessary parse-time lookup in the common case
        // where the syntax forbids a type.
        const Token &Next = NextToken();
  
        // If this identifier was reverted from a token ID, and the next token
        // is a parenthesis, this is likely to be a use of a type trait. Check
        // those tokens.
        if (Next.is(tok::l_paren) &&
            Tok.is(tok::identifier) &&
            Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
          IdentifierInfo *II = Tok.getIdentifierInfo();
          // Build up the mapping of revertible type traits, for future use.
          if (RevertibleTypeTraits.empty()) {
  #define RTT_JOIN(X,Y) X##Y
  #define REVERTIBLE_TYPE_TRAIT(Name)                         \
            RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
              = RTT_JOIN(tok::kw_,Name)
  
            REVERTIBLE_TYPE_TRAIT(__is_abstract);
            REVERTIBLE_TYPE_TRAIT(__is_aggregate);
            REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
            REVERTIBLE_TYPE_TRAIT(__is_array);
            REVERTIBLE_TYPE_TRAIT(__is_assignable);
            REVERTIBLE_TYPE_TRAIT(__is_base_of);
            REVERTIBLE_TYPE_TRAIT(__is_class);
            REVERTIBLE_TYPE_TRAIT(__is_complete_type);
            REVERTIBLE_TYPE_TRAIT(__is_compound);
            REVERTIBLE_TYPE_TRAIT(__is_const);
            REVERTIBLE_TYPE_TRAIT(__is_constructible);
            REVERTIBLE_TYPE_TRAIT(__is_convertible);
            REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
            REVERTIBLE_TYPE_TRAIT(__is_destructible);
            REVERTIBLE_TYPE_TRAIT(__is_empty);
            REVERTIBLE_TYPE_TRAIT(__is_enum);
            REVERTIBLE_TYPE_TRAIT(__is_floating_point);
            REVERTIBLE_TYPE_TRAIT(__is_final);
            REVERTIBLE_TYPE_TRAIT(__is_function);
            REVERTIBLE_TYPE_TRAIT(__is_fundamental);
            REVERTIBLE_TYPE_TRAIT(__is_integral);
            REVERTIBLE_TYPE_TRAIT(__is_interface_class);
            REVERTIBLE_TYPE_TRAIT(__is_literal);
            REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
            REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
            REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
            REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
            REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
            REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
            REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
            REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
            REVERTIBLE_TYPE_TRAIT(__is_object);
            REVERTIBLE_TYPE_TRAIT(__is_pod);
            REVERTIBLE_TYPE_TRAIT(__is_pointer);
            REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
            REVERTIBLE_TYPE_TRAIT(__is_reference);
            REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
            REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
            REVERTIBLE_TYPE_TRAIT(__is_same);
            REVERTIBLE_TYPE_TRAIT(__is_scalar);
            REVERTIBLE_TYPE_TRAIT(__is_sealed);
            REVERTIBLE_TYPE_TRAIT(__is_signed);
            REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
            REVERTIBLE_TYPE_TRAIT(__is_trivial);
            REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
            REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
            REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
            REVERTIBLE_TYPE_TRAIT(__is_union);
            REVERTIBLE_TYPE_TRAIT(__is_unsigned);
            REVERTIBLE_TYPE_TRAIT(__is_void);
            REVERTIBLE_TYPE_TRAIT(__is_volatile);
  #undef REVERTIBLE_TYPE_TRAIT
  #undef RTT_JOIN
          }
  
          // If we find that this is in fact the name of a type trait,
          // update the token kind in place and parse again to treat it as
          // the appropriate kind of type trait.
          llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
            = RevertibleTypeTraits.find(II);
          if (Known != RevertibleTypeTraits.end()) {
            Tok.setKind(Known->second);
            return ParseCastExpression(ParseKind, isAddressOfOperand,
                                       NotCastExpr, isTypeCast,
                                       isVectorLiteral, NotPrimaryExpression);
          }
        }
  
        if ((!ColonIsSacred && Next.is(tok::colon)) ||
            Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
                         tok::l_brace)) {
          // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
          if (TryAnnotateTypeOrScopeToken())
            return ExprError();
          if (!Tok.is(tok::identifier))
            return ParseCastExpression(ParseKind, isAddressOfOperand,
                                       NotCastExpr, isTypeCast,
                                       isVectorLiteral,
                                       NotPrimaryExpression);
        }
      }
  
      // Consume the identifier so that we can see if it is followed by a '(' or
      // '.'.
      IdentifierInfo &II = *Tok.getIdentifierInfo();
      SourceLocation ILoc = ConsumeToken();
  
      // Support 'Class.property' and 'super.property' notation.
      if (getLangOpts().ObjC && Tok.is(tok::period) &&
          (Actions.getTypeName(II, ILoc, getCurScope()) ||
           // Allow the base to be 'super' if in an objc-method.
           (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) {
        ConsumeToken();
  
        if (Tok.is(tok::code_completion) && &II != Ident_super) {
          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::TypeName);
              TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
                                                    DeclaratorInfo);
              if (Ty.isInvalid())
                break;
  
              Res = ParseObjCMessageExpressionBody(SourceLocation(),
                                                   SourceLocation(),
                                                   Ty.get(), nullptr);
              break;
            }
      }
  
      // Make sure to pass down the right value for isAddressOfOperand.
      if (isAddressOfOperand && isPostfixExpressionSuffixStart())
        isAddressOfOperand = false;
  
      // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
      // need to know whether or not this identifier is a function designator or
      // not.
      UnqualifiedId Name;
      CXXScopeSpec ScopeSpec;
      SourceLocation TemplateKWLoc;
      Token Replacement;
      CastExpressionIdValidator Validator(
          /*Next=*/Tok,
          /*AllowTypes=*/isTypeCast != NotTypeCast,
          /*AllowNonTypes=*/isTypeCast != IsTypeCast);
      Validator.IsAddressOfOperand = isAddressOfOperand;
      if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) {
        Validator.WantExpressionKeywords = false;
        Validator.WantRemainingKeywords = false;
      } else {
        Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren);
      }
      Name.setIdentifier(&II, ILoc);
      Res = Actions.ActOnIdExpression(
          getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
          isAddressOfOperand, &Validator,
          /*IsInlineAsmIdentifier=*/false,
          Tok.is(tok::r_paren) ? nullptr : &Replacement);
      if (!Res.isInvalid() && Res.isUnset()) {
        UnconsumeToken(Replacement);
        return ParseCastExpression(ParseKind, isAddressOfOperand,
                                   NotCastExpr, isTypeCast,
                                   /*isVectorLiteral=*/false,
                                   NotPrimaryExpression);
      }
      if (!Res.isInvalid() && Tok.is(tok::less))
        checkPotentialAngleBracket(Res);
      break;
    }
    case tok::char_constant:     // constant: character-constant
    case tok::wide_char_constant:
    case tok::utf8_char_constant:
    case tok::utf16_char_constant:
    case tok::utf32_char_constant:
      Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
      ConsumeToken();
      break;
    case tok::kw___func__:       // primary-expression: __func__ [C99 6.4.2.2]
    case tok::kw___FUNCTION__:   // primary-expression: __FUNCTION__ [GNU]
    case tok::kw___FUNCDNAME__:   // primary-expression: __FUNCDNAME__ [MS]
    case tok::kw___FUNCSIG__:     // primary-expression: __FUNCSIG__ [MS]
    case tok::kw_L__FUNCTION__:   // primary-expression: L__FUNCTION__ [MS]
    case tok::kw_L__FUNCSIG__:    // primary-expression: L__FUNCSIG__ [MS]
    case tok::kw___PRETTY_FUNCTION__:  // primary-expression: __P..Y_F..N__ [GNU]
      Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
      ConsumeToken();
      break;
    case tok::string_literal:    // primary-expression: string-literal
    case tok::wide_string_literal:
    case tok::utf8_string_literal:
    case tok::utf16_string_literal:
    case tok::utf32_string_literal:
      Res = ParseStringLiteralExpression(true);
      break;
    case tok::kw__Generic:   // primary-expression: generic-selection [C11 6.5.1]
      Res = ParseGenericSelectionExpression();
      break;
    case tok::kw___builtin_available:
      Res = ParseAvailabilityCheckExpr(Tok.getLocation());
      break;
    case tok::kw___builtin_va_arg:
    case tok::kw___builtin_offsetof:
    case tok::kw___builtin_choose_expr:
    case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
    case tok::kw___builtin_convertvector:
    case tok::kw___builtin_COLUMN:
    case tok::kw___builtin_FILE:
    case tok::kw___builtin_FUNCTION:
    case tok::kw___builtin_LINE:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      // This parses the complete suffix; we can return early.
      return ParseBuiltinPrimaryExpression();
    case tok::kw___null:
      Res = Actions.ActOnGNUNullExpr(ConsumeToken());
      break;
  
    case tok::plusplus:      // unary-expression: '++' unary-expression [C99]
    case tok::minusminus: {  // unary-expression: '--' unary-expression [C99]
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      // C++ [expr.unary] has:
      //   unary-expression:
      //     ++ cast-expression
      //     -- cast-expression
      Token SavedTok = Tok;
      ConsumeToken();
  
      PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(),
                               SavedTok.getLocation());
      // One special case is implicitly handled here: if the preceding tokens are
      // an ambiguous cast expression, such as "(T())++", then we recurse to
      // determine whether the '++' is prefix or postfix.
      Res = ParseCastExpression(getLangOpts().CPlusPlus ?
                                    UnaryExprOnly : AnyCastExpr,
                                /*isAddressOfOperand*/false, NotCastExpr,
                                NotTypeCast);
      if (NotCastExpr) {
        // If we return with NotCastExpr = true, we must not consume any tokens,
        // so put the token back where we found it.
        assert(Res.isInvalid());
        UnconsumeToken(SavedTok);
        return ExprError();
      }
      if (!Res.isInvalid()) {
        Expr *Arg = Res.get();
        Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(),
                                   SavedKind, Arg);
        if (Res.isInvalid())
          Res = Actions.CreateRecoveryExpr(SavedTok.getLocation(),
                                           Arg->getEndLoc(), Arg);
      }
      return Res;
    }
    case tok::amp: {         // unary-expression: '&' cast-expression
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      // Special treatment because of member pointers
      SourceLocation SavedLoc = ConsumeToken();
      PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc);
      Res = ParseCastExpression(AnyCastExpr, true);
      if (!Res.isInvalid()) {
        Expr *Arg = Res.get();
        Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
        if (Res.isInvalid())
          Res = Actions.CreateRecoveryExpr(Tok.getLocation(), Arg->getEndLoc(),
                                           Arg);
      }
      return Res;
    }
  
    case tok::star:          // unary-expression: '*' cast-expression
    case tok::plus:          // unary-expression: '+' cast-expression
    case tok::minus:         // unary-expression: '-' cast-expression
    case tok::tilde:         // unary-expression: '~' cast-expression
    case tok::exclaim:       // unary-expression: '!' cast-expression
    case tok::kw___real:     // unary-expression: '__real' cast-expression [GNU]
    case tok::kw___imag: {   // unary-expression: '__imag' cast-expression [GNU]
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      SourceLocation SavedLoc = ConsumeToken();
      PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc);
      Res = ParseCastExpression(AnyCastExpr);
      if (!Res.isInvalid()) {
        Expr *Arg = Res.get();
        Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
        if (Res.isInvalid())
          Res = Actions.CreateRecoveryExpr(SavedLoc, Arg->getEndLoc(), Arg);
      }
      return Res;
    }
  
    case tok::kw_co_await: {  // unary-expression: 'co_await' cast-expression
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      SourceLocation CoawaitLoc = ConsumeToken();
      Res = ParseCastExpression(AnyCastExpr);
      if (!Res.isInvalid())
        Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get());
      return Res;
    }
  
    case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
      // __extension__ silences extension warnings in the subexpression.
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      ExtensionRAIIObject O(Diags);  // Use RAII to do this.
      SourceLocation SavedLoc = ConsumeToken();
      Res = ParseCastExpression(AnyCastExpr);
      if (!Res.isInvalid())
        Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
      return Res;
    }
    case tok::kw__Alignof:   // unary-expression: '_Alignof' '(' type-name ')'
      if (!getLangOpts().C11)
        Diag(Tok, diag::ext_c11_feature) << Tok.getName();
      LLVM_FALLTHROUGH;
    case tok::kw_alignof:    // unary-expression: 'alignof' '(' type-id ')'
    case tok::kw___alignof:  // unary-expression: '__alignof' unary-expression
                             // unary-expression: '__alignof' '(' type-name ')'
    case tok::kw_sizeof:     // unary-expression: 'sizeof' unary-expression
                             // unary-expression: 'sizeof' '(' type-name ')'
    case tok::kw_vec_step:   // unary-expression: OpenCL 'vec_step' expression
    // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
    case tok::kw___builtin_omp_required_simd_align:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      AllowSuffix = false;
      Res = ParseUnaryExprOrTypeTraitExpression();
      break;
    case tok::ampamp: {      // unary-expression: '&&' identifier
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      SourceLocation AmpAmpLoc = ConsumeToken();
      if (Tok.isNot(tok::identifier))
        return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
  
      if (getCurScope()->getFnParent() == nullptr)
        return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn));
  
      Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
      LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
                                                  Tok.getLocation());
      Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD);
      ConsumeToken();
      AllowSuffix = false;
      break;
    }
    case tok::kw_const_cast:
    case tok::kw_dynamic_cast:
    case tok::kw_reinterpret_cast:
    case tok::kw_static_cast:
    case tok::kw_addrspace_cast:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseCXXCasts();
      break;
    case tok::kw___builtin_bit_cast:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseBuiltinBitCast();
      break;
    case tok::kw_typeid:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseCXXTypeid();
      break;
    case tok::kw___uuidof:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseCXXUuidof();
      break;
    case tok::kw_this:
      Res = ParseCXXThis();
      break;
  
    case tok::annot_typename:
      if (isStartOfObjCClassMessageMissingOpenBracket()) {
        TypeResult Type = getTypeAnnotation(Tok);
  
        // Fake up a Declarator to use with ActOnTypeName.
        DeclSpec DS(AttrFactory);
        DS.SetRangeStart(Tok.getLocation());
        DS.SetRangeEnd(Tok.getLastLoc());
  
        const char *PrevSpec = nullptr;
        unsigned DiagID;
        DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
                           PrevSpec, DiagID, Type,
                           Actions.getASTContext().getPrintingPolicy());
  
        Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
        TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
        if (Ty.isInvalid())
          break;
  
        ConsumeAnnotationToken();
        Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
                                             Ty.get(), nullptr);
        break;
      }
      LLVM_FALLTHROUGH;
  
    case tok::annot_decltype:
    case tok::kw_char:
    case tok::kw_wchar_t:
    case tok::kw_char8_t:
    case tok::kw_char16_t:
    case tok::kw_char32_t:
    case tok::kw_bool:
    case tok::kw_short:
    case tok::kw_int:
    case tok::kw_long:
    case tok::kw___int64:
    case tok::kw___int128:
    case tok::kw__ExtInt:
    case tok::kw_signed:
    case tok::kw_unsigned:
    case tok::kw_half:
    case tok::kw_float:
    case tok::kw_double:
    case tok::kw___bf16:
    case tok::kw__Float16:
    case tok::kw___float128:
    case tok::kw_void:
    case tok::kw_typename:
    case tok::kw_typeof:
    case tok::kw___vector:
  #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
  #include "clang/Basic/OpenCLImageTypes.def"
    {
      if (!getLangOpts().CPlusPlus) {
        Diag(Tok, diag::err_expected_expression);
        return ExprError();
      }
  
      // Everything henceforth is a postfix-expression.
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
  
      if (SavedKind == tok::kw_typename) {
        // postfix-expression: typename-specifier '(' expression-list[opt] ')'
        //                     typename-specifier braced-init-list
        if (TryAnnotateTypeOrScopeToken())
          return ExprError();
  
        if (!Actions.isSimpleTypeSpecifier(Tok.getKind()))
          // We are trying to parse a simple-type-specifier but might not get such
          // a token after error recovery.
          return ExprError();
      }
  
      // postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
      //                     simple-type-specifier braced-init-list
      //
      DeclSpec DS(AttrFactory);
  
      ParseCXXSimpleTypeSpecifier(DS);
      if (Tok.isNot(tok::l_paren) &&
          (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
        return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
                           << DS.getSourceRange());
  
      if (Tok.is(tok::l_brace))
        Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
  
      Res = ParseCXXTypeConstructExpression(DS);
      break;
    }
  
    case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
      // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
      // (We can end up in this situation after tentative parsing.)
      if (TryAnnotateTypeOrScopeToken())
        return ExprError();
      if (!Tok.is(tok::annot_cxxscope))
        return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
                                   isTypeCast, isVectorLiteral,
                                   NotPrimaryExpression);
  
      Token Next = NextToken();
      if (Next.is(tok::annot_template_id)) {
        TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
        if (TemplateId->Kind == TNK_Type_template) {
          // We have a qualified template-id that we know refers to a
          // type, translate it into a type and continue parsing as a
          // cast expression.
          CXXScopeSpec SS;
          ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
                                         /*ObjectHadErrors=*/false,
                                         /*EnteringContext=*/false);
          AnnotateTemplateIdTokenAsType(SS);
          return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
                                     isTypeCast, isVectorLiteral,
                                     NotPrimaryExpression);
        }
      }
  
      // Parse as an id-expression.
      Res = ParseCXXIdExpression(isAddressOfOperand);
      break;
    }
  
    case tok::annot_template_id: { // [C++]          template-id
      TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
      if (TemplateId->Kind == TNK_Type_template) {
        // We have a template-id that we know refers to a type,
        // translate it into a type and continue parsing as a cast
        // expression.
        CXXScopeSpec SS;
        AnnotateTemplateIdTokenAsType(SS);
        return ParseCastExpression(ParseKind, isAddressOfOperand,
                                   NotCastExpr, isTypeCast, isVectorLiteral,
                                   NotPrimaryExpression);
      }
  
      // Fall through to treat the template-id as an id-expression.
      LLVM_FALLTHROUGH;
    }
  
    case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
      Res = ParseCXXIdExpression(isAddressOfOperand);
      break;
  
    case tok::coloncolon: {
      // ::foo::bar -> global qualified name etc.   If TryAnnotateTypeOrScopeToken
      // annotates the token, tail recurse.
      if (TryAnnotateTypeOrScopeToken())
        return ExprError();
      if (!Tok.is(tok::coloncolon))
        return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
                                   isVectorLiteral, NotPrimaryExpression);
  
      // ::new -> [C++] new-expression
      // ::delete -> [C++] delete-expression
      SourceLocation CCLoc = ConsumeToken();
      if (Tok.is(tok::kw_new)) {
        if (NotPrimaryExpression)
          *NotPrimaryExpression = true;
        Res = ParseCXXNewExpression(true, CCLoc);
        AllowSuffix = false;
        break;
      }
      if (Tok.is(tok::kw_delete)) {
        if (NotPrimaryExpression)
          *NotPrimaryExpression = true;
        Res = ParseCXXDeleteExpression(true, CCLoc);
        AllowSuffix = false;
        break;
      }
  
      // This is not a type name or scope specifier, it is an invalid expression.
      Diag(CCLoc, diag::err_expected_expression);
      return ExprError();
    }
  
    case tok::kw_new: // [C++] new-expression
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseCXXNewExpression(false, Tok.getLocation());
      AllowSuffix = false;
      break;
  
    case tok::kw_delete: // [C++] delete-expression
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseCXXDeleteExpression(false, Tok.getLocation());
      AllowSuffix = false;
      break;
  
    case tok::kw_requires: // [C++2a] requires-expression
      Res = ParseRequiresExpression();
      AllowSuffix = false;
      break;
  
    case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Diag(Tok, diag::warn_cxx98_compat_noexcept_expr);
      SourceLocation KeyLoc = ConsumeToken();
      BalancedDelimiterTracker T(*this, tok::l_paren);
  
      if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
        return ExprError();
      // C++11 [expr.unary.noexcept]p1:
      //   The noexcept operator determines whether the evaluation of its operand,
      //   which is an unevaluated operand, can throw an exception.
      EnterExpressionEvaluationContext Unevaluated(
          Actions, Sema::ExpressionEvaluationContext::Unevaluated);
      Res = ParseExpression();
  
      T.consumeClose();
  
      if (!Res.isInvalid())
        Res = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Res.get(),
                                        T.getCloseLocation());
      AllowSuffix = false;
      break;
    }
  
  #define TYPE_TRAIT(N,Spelling,K) \
    case tok::kw_##Spelling:
  #include "clang/Basic/TokenKinds.def"
      Res = ParseTypeTrait();
      break;
  
    case tok::kw___array_rank:
    case tok::kw___array_extent:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseArrayTypeTrait();
      break;
  
    case tok::kw___is_lvalue_expr:
    case tok::kw___is_rvalue_expr:
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      Res = ParseExpressionTrait();
      break;
  
    case tok::at: {
      if (NotPrimaryExpression)
        *NotPrimaryExpression = true;
      SourceLocation AtLoc = ConsumeToken();
      return ParseObjCAtExpression(AtLoc);
    }
    case tok::caret:
      Res = ParseBlockLiteralExpression();
      break;
    case tok::code_completion: {
      Actions.CodeCompleteExpression(getCurScope(),
                                     PreferredType.get(Tok.getLocation()));
      cutOffParsing();
      return ExprError();
    }
    // postfix-expression: [CP]
    //   _Cilk_spawn[opt] postfix-expression '(' argument-expression-list[opt] ')'
    case tok::kw__Cilk_spawn: {
      SourceLocation SpawnLoc = ConsumeToken();
      // if (!getLangOpts().Cilk) {
      //   Diag(SpawnLoc, diag::err_cilkplus_disable);
      //   SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
      //   return ExprError();
      // }
  
      Res = ParseCastExpression(AnyCastExpr);
      if (!Res.isInvalid())
        Res = Actions.ActOnCilkSpawnExpr(SpawnLoc, Res.get());
      return Res;
    }
    case tok::l_square:
      if (getLangOpts().CPlusPlus11) {
        if (getLangOpts().ObjC) {
          // C++11 lambda expressions and Objective-C message sends both start with a
          // square bracket.  There are three possibilities here:
          // we have a valid lambda expression, we have an invalid lambda
          // expression, or we have something that doesn't appear to be a lambda.
          // If we're in the last case, we fall back to ParseObjCMessageExpression.
          Res = TryParseLambdaExpression();
          if (!Res.isInvalid() && !Res.get()) {
            // We assume Objective-C++ message expressions are not
            // primary-expressions.
            if (NotPrimaryExpression)
              *NotPrimaryExpression = true;
            Res = ParseObjCMessageExpression();
          }
          break;
        }
        Res = ParseLambdaExpression();
        break;
      }
      if (getLangOpts().ObjC) {
        Res = ParseObjCMessageExpression();
        break;
      }
      LLVM_FALLTHROUGH;
    default:
      NotCastExpr = true;
      return ExprError();
    }
  
    // Check to see whether Res is a function designator only. If it is and we
    // are compiling for OpenCL, we need to return an error as this implies
    // that the address of the function is being taken, which is illegal in CL.
  
    if (ParseKind == PrimaryExprOnly)
      // This is strictly a primary-expression - no postfix-expr pieces should be
      // parsed.
      return Res;
  
    if (!AllowSuffix) {
      // FIXME: Don't parse a primary-expression suffix if we encountered a parse
      // error already.
      if (Res.isInvalid())
        return Res;
  
      switch (Tok.getKind()) {
      case tok::l_square:
      case tok::l_paren:
      case tok::plusplus:
      case tok::minusminus:
        // "expected ';'" or similar is probably the right diagnostic here. Let
        // the caller decide what to do.
        if (Tok.isAtStartOfLine())
          return Res;
  
        LLVM_FALLTHROUGH;
      case tok::period:
      case tok::arrow:
        break;
  
      default:
        return Res;
      }
  
      // This was a unary-expression for which a postfix-expression suffix is
      // not permitted by the grammar (eg, a sizeof expression or
      // new-expression or similar). Diagnose but parse the suffix anyway.
      Diag(Tok.getLocation(), diag::err_postfix_after_unary_requires_parens)
          << Tok.getKind() << Res.get()->getSourceRange()
          << FixItHint::CreateInsertion(Res.get()->getBeginLoc(), "(")
          << FixItHint::CreateInsertion(PP.getLocForEndOfToken(PrevTokLocation),
                                        ")");
    }
  
    // These can be followed by postfix-expr pieces.
    PreferredType = SavedType;
    Res = ParsePostfixExpressionSuffix(Res);
    if (getLangOpts().OpenCL)
      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, Stride;
        SourceLocation ColonLocFirst, ColonLocSecond;
        PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
        if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
          Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
          Idx = ParseBraceInitializer();
        } else if (getLangOpts().OpenMP) {
          ColonProtectionRAIIObject RAII(*this);
          // Parse [: or [ expr or [ expr :
          if (!Tok.is(tok::colon)) {
            // [ expr
            Idx = ParseExpression();
          }
          if (Tok.is(tok::colon)) {
            // Consume ':'
            ColonLocFirst = ConsumeToken();
            if (Tok.isNot(tok::r_square) &&
                (getLangOpts().OpenMP < 50 ||
                 ((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50))))
              Length = ParseExpression();
          }
          if (getLangOpts().OpenMP >= 50 &&
              (OMPClauseKind == llvm::omp::Clause::OMPC_to ||
               OMPClauseKind == llvm::omp::Clause::OMPC_from) &&
              Tok.is(tok::colon)) {
            // Consume ':'
            ColonLocSecond = ConsumeToken();
            if (Tok.isNot(tok::r_square)) {
              Stride = ParseExpression();
            }
          }
        } else
          Idx = ParseExpression();
  
        SourceLocation RLoc = Tok.getLocation();
  
        LHS = Actions.CorrectDelayedTyposInExpr(LHS);
        Idx = Actions.CorrectDelayedTyposInExpr(Idx);
        Length = Actions.CorrectDelayedTyposInExpr(Length);
        if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() &&
            !Stride.isInvalid() && Tok.is(tok::r_square)) {
          if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
            LHS = Actions.ActOnOMPArraySectionExpr(
                LHS.get(), Loc, Idx.get(), ColonLocFirst, ColonLocSecond,
                Length.get(), Stride.get(), RLoc);
          } else {
            LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
                                                  Idx.get(), RLoc);
          }
        } else {
          LHS = ExprError();
          Idx = ExprError();
        }
  
        // Match the ']'.
        T.consumeClose();
        break;
      }
  
      case tok::l_paren:         // p-e: p-e '(' argument-expression-list[opt] ')'
      case tok::lesslessless: {  // p-e: p-e '<<<' argument-expression-list '>>>'
                                 //   '(' argument-expression-list[opt] ')'
        tok::TokenKind OpKind = Tok.getKind();
        InMessageExpressionRAIIObject InMessage(*this, false);
  
        Expr *ExecConfig = nullptr;
  
        BalancedDelimiterTracker PT(*this, tok::l_paren);
  
        if (OpKind == tok::lesslessless) {
          ExprVector ExecConfigExprs;
          CommaLocsTy ExecConfigCommaLocs;
          SourceLocation OpenLoc = ConsumeToken();
  
          if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
            (void)Actions.CorrectDelayedTyposInExpr(LHS);
            LHS = ExprError();
          }
  
          SourceLocation CloseLoc;
          if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) {
          } else if (LHS.isInvalid()) {
            SkipUntil(tok::greatergreatergreater, StopAtSemi);
          } else {
            // There was an error closing the brackets
            Diag(Tok, diag::err_expected) << tok::greatergreatergreater;
            Diag(OpenLoc, diag::note_matching) << tok::lesslessless;
            SkipUntil(tok::greatergreatergreater, StopAtSemi);
            LHS = ExprError();
          }
  
          if (!LHS.isInvalid()) {
            if (ExpectAndConsume(tok::l_paren))
              LHS = ExprError();
            else
              Loc = PrevTokLocation;
          }
  
          if (!LHS.isInvalid()) {
            ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
                                      OpenLoc,
                                      ExecConfigExprs,
                                      CloseLoc);
            if (ECResult.isInvalid())
              LHS = ExprError();
            else
              ExecConfig = ECResult.get();
          }
        } else {
          PT.consumeOpen();
          Loc = PT.getOpenLocation();
        }
  
        ExprVector ArgExprs;
        CommaLocsTy CommaLocs;
        auto RunSignatureHelp = [&]() -> QualType {
          QualType PreferredType = Actions.ProduceCallSignatureHelp(
              getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation());
          CalledSignatureHelp = true;
          return PreferredType;
        };
        if (OpKind == tok::l_paren || !LHS.isInvalid()) {
          if (Tok.isNot(tok::r_paren)) {
            if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
                  PreferredType.enterFunctionArgument(Tok.getLocation(),
                                                      RunSignatureHelp);
                })) {
              (void)Actions.CorrectDelayedTyposInExpr(LHS);
              // If we got an error when parsing expression list, we don't call
              // the CodeCompleteCall handler inside the parser. So call it here
              // to make sure we get overload suggestions even when we are in the
              // middle of a parameter.
              if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
                RunSignatureHelp();
              LHS = ExprError();
            } else if (LHS.isInvalid()) {
              for (auto &E : ArgExprs)
                Actions.CorrectDelayedTyposInExpr(E);
            }
          }
        }
  
        // Match the ')'.
        if (LHS.isInvalid()) {
          SkipUntil(tok::r_paren, StopAtSemi);
        } else if (Tok.isNot(tok::r_paren)) {
          bool HadDelayedTypo = false;
          if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get())
            HadDelayedTypo = true;
          for (auto &E : ArgExprs)
            if (Actions.CorrectDelayedTyposInExpr(E).get() != E)
              HadDelayedTypo = true;
          // If there were delayed typos in the LHS or ArgExprs, call SkipUntil
          // instead of PT.consumeClose() to avoid emitting extra diagnostics for
          // the unmatched l_paren.
          if (HadDelayedTypo)
            SkipUntil(tok::r_paren, StopAtSemi);
          else
            PT.consumeClose();
          LHS = ExprError();
        } else {
          assert(
              (ArgExprs.size() == 0 || ArgExprs.size() - 1 == CommaLocs.size()) &&
              "Unexpected number of commas!");
          Expr *Fn = LHS.get();
          SourceLocation RParLoc = Tok.getLocation();
          LHS = Actions.ActOnCallExpr(getCurScope(), Fn, Loc, ArgExprs, RParLoc,
                                      ExecConfig);
          if (LHS.isInvalid()) {
            ArgExprs.insert(ArgExprs.begin(), Fn);
            LHS =
                Actions.CreateRecoveryExpr(Fn->getBeginLoc(), RParLoc, ArgExprs);
          }
          PT.consumeClose();
        }
  
        break;
      }
      case tok::arrow:
      case tok::period: {
        // postfix-expression: p-e '->' template[opt] id-expression
        // postfix-expression: p-e '.' template[opt] id-expression
        tok::TokenKind OpKind = Tok.getKind();
        SourceLocation OpLoc = ConsumeToken();  // Eat the "." or "->" token.
  
        CXXScopeSpec SS;
        ParsedType ObjectType;
        bool MayBePseudoDestructor = false;
        Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr;
  
        PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS);
  
        if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
          Expr *Base = OrigLHS;
          const Type* BaseType = Base->getType().getTypePtrOrNull();
          if (BaseType && Tok.is(tok::l_paren) &&
              (BaseType->isFunctionType() ||
               BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) {
            Diag(OpLoc, diag::err_function_is_not_record)
                << OpKind << Base->getSourceRange()
                << FixItHint::CreateRemoval(OpLoc);
            return ParsePostfixExpressionSuffix(Base);
          }
  
          LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, OpLoc,
                                                     OpKind, ObjectType,
                                                     MayBePseudoDestructor);
          if (LHS.isInvalid()) {
            // Clang will try to perform expression based completion as a
            // fallback, which is confusing in case of member references. So we
            // stop here without any completions.
            if (Tok.is(tok::code_completion)) {
              cutOffParsing();
              return ExprError();
            }
            break;
          }
          ParseOptionalCXXScopeSpecifier(
              SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
              /*EnteringContext=*/false, &MayBePseudoDestructor);
          if (SS.isNotEmpty())
            ObjectType = nullptr;
        }
  
        if (Tok.is(tok::code_completion)) {
          tok::TokenKind CorrectedOpKind =
              OpKind == tok::arrow ? tok::period : tok::arrow;
          ExprResult CorrectedLHS(/*Invalid=*/true);
          if (getLangOpts().CPlusPlus && OrigLHS) {
            // FIXME: Creating a TentativeAnalysisScope from outside Sema is a
            // hack.
            Sema::TentativeAnalysisScope Trap(Actions);
            CorrectedLHS = Actions.ActOnStartCXXMemberReference(
                getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType,
                MayBePseudoDestructor);
          }
  
          Expr *Base = LHS.get();
          Expr *CorrectedBase = CorrectedLHS.get();
          if (!CorrectedBase && !getLangOpts().CPlusPlus)
            CorrectedBase = Base;
  
          // Code completion for a member access expression.
          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, ObjectType, LHS.get() && LHS.get()->containsErrors(),
                       /*EnteringContext=*/false,
                       /*AllowDestructorName=*/true,
                       /*AllowConstructorName=*/
                       getLangOpts().MicrosoftExt && SS.isNotEmpty(),
                       /*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) {
          (void)Actions.CorrectDelayedTyposInExpr(LHS);
          LHS = ExprError();
        }
  
        if (!LHS.isInvalid())
          LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
                                              OpKind, SS, TemplateKWLoc, Name,
                                   CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
                                                     : nullptr);
        if (!LHS.isInvalid()) {
          if (Tok.is(tok::less))
            checkPotentialAngleBracket(LHS);
        } else if (OrigLHS && Name.isValid()) {
          // Preserve the LHS if the RHS is an invalid member.
          LHS = Actions.CreateRecoveryExpr(OrigLHS->getBeginLoc(),
                                           Name.getEndLoc(), {OrigLHS});
        }
        break;
      }
      case tok::plusplus:    // postfix-expression: postfix-expression '++'
      case tok::minusminus:  // postfix-expression: postfix-expression '--'
        if (!LHS.isInvalid()) {
          Expr *Arg = LHS.get();
          LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(),
                                            Tok.getKind(), Arg);
          if (LHS.isInvalid())
            LHS = Actions.CreateRecoveryExpr(Arg->getBeginLoc(),
                                             Tok.getLocation(), Arg);
        }
        ConsumeToken();
        break;
      }
    }
  }
  
  /// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/
  /// vec_step and we are at the start of an expression or a parenthesized
  /// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the
  /// expression (isCastExpr == false) or the type (isCastExpr == true).
  ///
  /// \verbatim
  ///       unary-expression:  [C99 6.5.3]
  ///         'sizeof' unary-expression
  ///         'sizeof' '(' type-name ')'
  /// [GNU]   '__alignof' unary-expression
  /// [GNU]   '__alignof' '(' type-name ')'
  /// [C11]   '_Alignof' '(' type-name ')'
  /// [C++0x] 'alignof' '(' type-id ')'
  ///
  /// [GNU]   typeof-specifier:
  ///           typeof ( expressions )
  ///           typeof ( type-name )
  /// [GNU/C++] typeof unary-expression
  ///
  /// [OpenCL 1.1 6.11.12] vec_step built-in function:
  ///           vec_step ( expressions )
  ///           vec_step ( type-name )
  /// \endverbatim
  ExprResult
  Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
                                             bool &isCastExpr,
                                             ParsedType &CastTy,
                                             SourceRange &CastRange) {
  
    assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof,
                         tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step,
                         tok::kw___builtin_omp_required_simd_align) &&
           "Not a typeof/sizeof/alignof/vec_step expression!");
  
    ExprResult Operand;
  
    // If the operand doesn't start with an '(', it must be an expression.
    if (Tok.isNot(tok::l_paren)) {
      // If construct allows a form without parenthesis, user may forget to put
      // pathenthesis around type name.
      if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
                        tok::kw__Alignof)) {
        if (isTypeIdUnambiguously()) {
          DeclSpec DS(AttrFactory);
          ParseSpecifierQualifierList(DS);
          Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
          ParseDeclarator(DeclaratorInfo);
  
          SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation());
          SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation);
          if (LParenLoc.isInvalid() || RParenLoc.isInvalid()) {
            Diag(OpTok.getLocation(),
                 diag::err_expected_parentheses_around_typename)
                << OpTok.getName();
          } else {
            Diag(LParenLoc, diag::err_expected_parentheses_around_typename)
                << OpTok.getName() << FixItHint::CreateInsertion(LParenLoc, "(")
                << FixItHint::CreateInsertion(RParenLoc, ")");
          }
          isCastExpr = true;
          return ExprEmpty();
        }
      }
  
      isCastExpr = false;
      if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
        Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo()
                                            << tok::l_paren;
        return ExprError();
      }
  
      Operand = ParseCastExpression(UnaryExprOnly);
    } else {
      // If it starts with a '(', we know that it is either a parenthesized
      // type-name, or it is a unary-expression that starts with a compound
      // literal, or starts with a primary-expression that is a parenthesized
      // expression.
      ParenParseOption ExprType = CastExpr;
      SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
  
      Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
                                     false, CastTy, RParenLoc);
      CastRange = SourceRange(LParenLoc, RParenLoc);
  
      // If ParseParenExpression parsed a '(typename)' sequence only, then this is
      // a type.
      if (ExprType == CastExpr) {
        isCastExpr = true;
        return ExprEmpty();
      }
  
      if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) {
        // GNU typeof in C requires the expression to be parenthesized. Not so for
        // sizeof/alignof or in C++. Therefore, the parenthesized expression is
        // the start of a unary-expression, but doesn't include any postfix
        // pieces. Parse these now if present.
        if (!Operand.isInvalid())
          Operand = ParsePostfixExpressionSuffix(Operand.get());
      }
    }
  
    // If we get here, the operand to the typeof/sizeof/alignof was an expression.
    isCastExpr = false;
    return Operand;
  }
  
  
  /// Parse a sizeof or alignof expression.
  ///
  /// \verbatim
  ///       unary-expression:  [C99 6.5.3]
  ///         'sizeof' unary-expression
  ///         'sizeof' '(' type-name ')'
  /// [C++11] 'sizeof' '...' '(' identifier ')'
  /// [GNU]   '__alignof' unary-expression
  /// [GNU]   '__alignof' '(' type-name ')'
  /// [C11]   '_Alignof' '(' type-name ')'
  /// [C++11] 'alignof' '(' type-id ')'
  /// \endverbatim
  ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
    assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
                       tok::kw__Alignof, tok::kw_vec_step,
                       tok::kw___builtin_omp_required_simd_align) &&
           "Not a sizeof/alignof/vec_step expression!");
    Token OpTok = Tok;
    ConsumeToken();
  
    // [C++11] 'sizeof' '...' '(' identifier ')'
    if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
      SourceLocation EllipsisLoc = ConsumeToken();
      SourceLocation LParenLoc, RParenLoc;
      IdentifierInfo *Name = nullptr;
      SourceLocation NameLoc;
      if (Tok.is(tok::l_paren)) {
        BalancedDelimiterTracker T(*this, tok::l_paren);
        T.consumeOpen();
        LParenLoc = T.getOpenLocation();
        if (Tok.is(tok::identifier)) {
          Name = Tok.getIdentifierInfo();
          NameLoc = ConsumeToken();
          T.consumeClose();
          RParenLoc = T.getCloseLocation();
          if (RParenLoc.isInvalid())
            RParenLoc = PP.getLocForEndOfToken(NameLoc);
        } else {
          Diag(Tok, diag::err_expected_parameter_pack);
          SkipUntil(tok::r_paren, StopAtSemi);
        }
      } else if (Tok.is(tok::identifier)) {
        Name = Tok.getIdentifierInfo();
        NameLoc = ConsumeToken();
        LParenLoc = PP.getLocForEndOfToken(EllipsisLoc);
        RParenLoc = PP.getLocForEndOfToken(NameLoc);
        Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack)
          << Name
          << FixItHint::CreateInsertion(LParenLoc, "(")
          << FixItHint::CreateInsertion(RParenLoc, ")");
      } else {
        Diag(Tok, diag::err_sizeof_parameter_pack);
      }
  
      if (!Name)
        return ExprError();
  
      EnterExpressionEvaluationContext Unevaluated(
          Actions, Sema::ExpressionEvaluationContext::Unevaluated,
          Sema::ReuseLambdaContextDecl);
  
      return Actions.ActOnSizeofParameterPackExpr(getCurScope(),
                                                  OpTok.getLocation(),
                                                  *Name, NameLoc,
                                                  RParenLoc);
    }
  
    if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
      Diag(OpTok, diag::warn_cxx98_compat_alignof);
  
    EnterExpressionEvaluationContext Unevaluated(
        Actions, Sema::ExpressionEvaluationContext::Unevaluated,
        Sema::ReuseLambdaContextDecl);
  
    bool isCastExpr;
    ParsedType CastTy;
    SourceRange CastRange;
    ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok,
                                                            isCastExpr,
                                                            CastTy,
                                                            CastRange);
  
    UnaryExprOrTypeTrait ExprKind = UETT_SizeOf;
    if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
      ExprKind = UETT_AlignOf;
    else if (OpTok.is(tok::kw___alignof))
      ExprKind = UETT_PreferredAlignOf;
    else if (OpTok.is(tok::kw_vec_step))
      ExprKind = UETT_VecStep;
    else if (OpTok.is(tok::kw___builtin_omp_required_simd_align))
      ExprKind = UETT_OpenMPRequiredSimdAlign;
  
    if (isCastExpr)
      return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
                                                   ExprKind,
                                                   /*IsType=*/true,
                                                   CastTy.getAsOpaquePtr(),
                                                   CastRange);
  
    if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
      Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
  
    // If we get here, the operand to the sizeof/alignof was an expression.
    if (!Operand.isInvalid())
      Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
                                                      ExprKind,
                                                      /*IsType=*/false,
                                                      Operand.get(),
                                                      CastRange);
    return Operand;
  }
  
  /// ParseBuiltinPrimaryExpression
  ///
  /// \verbatim
  ///       primary-expression: [C99 6.5.1]
  /// [GNU]   '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
  /// [GNU]   '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
  /// [GNU]   '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
  ///                                     assign-expr ')'
  /// [GNU]   '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
  /// [GNU]   '__builtin_FILE' '(' ')'
  /// [GNU]   '__builtin_FUNCTION' '(' ')'
  /// [GNU]   '__builtin_LINE' '(' ')'
  /// [CLANG] '__builtin_COLUMN' '(' ')'
  /// [OCL]   '__builtin_astype' '(' assignment-expression ',' type-name ')'
  ///
  /// [GNU] offsetof-member-designator:
  /// [GNU]   identifier
  /// [GNU]   offsetof-member-designator '.' identifier
  /// [GNU]   offsetof-member-designator '[' expression ']'
  /// \endverbatim
  ExprResult Parser::ParseBuiltinPrimaryExpression() {
    ExprResult Res;
    const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
  
    tok::TokenKind T = Tok.getKind();
    SourceLocation StartLoc = ConsumeToken();   // Eat the builtin identifier.
  
    // All of these start with an open paren.
    if (Tok.isNot(tok::l_paren))
      return ExprError(Diag(Tok, diag::err_expected_after) << BuiltinII
                                                           << tok::l_paren);
  
    BalancedDelimiterTracker PT(*this, tok::l_paren);
    PT.consumeOpen();
  
    // TODO: Build AST.
  
    switch (T) {
    default: llvm_unreachable("Not a builtin primary expression!");
    case tok::kw___builtin_va_arg: {
      ExprResult Expr(ParseAssignmentExpression());
  
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        Expr = ExprError();
      }
  
      TypeResult Ty = ParseTypeName();
  
      if (Tok.isNot(tok::r_paren)) {
        Diag(Tok, diag::err_expected) << tok::r_paren;
        Expr = ExprError();
      }
  
      if (Expr.isInvalid() || Ty.isInvalid())
        Res = ExprError();
      else
        Res = Actions.ActOnVAArg(StartLoc, Expr.get(), Ty.get(), ConsumeParen());
      break;
    }
    case tok::kw___builtin_offsetof: {
      SourceLocation TypeLoc = Tok.getLocation();
      TypeResult Ty = ParseTypeName();
      if (Ty.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      // We must have at least one identifier here.
      if (Tok.isNot(tok::identifier)) {
        Diag(Tok, diag::err_expected) << tok::identifier;
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      // Keep track of the various subcomponents we see.
      SmallVector<Sema::OffsetOfComponent, 4> Comps;
  
      Comps.push_back(Sema::OffsetOfComponent());
      Comps.back().isBrackets = false;
      Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
      Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
  
      // FIXME: This loop leaks the index expressions on error.
      while (1) {
        if (Tok.is(tok::period)) {
          // offsetof-member-designator: offsetof-member-designator '.' identifier
          Comps.push_back(Sema::OffsetOfComponent());
          Comps.back().isBrackets = false;
          Comps.back().LocStart = ConsumeToken();
  
          if (Tok.isNot(tok::identifier)) {
            Diag(Tok, diag::err_expected) << tok::identifier;
            SkipUntil(tok::r_paren, StopAtSemi);
            return ExprError();
          }
          Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
          Comps.back().LocEnd = ConsumeToken();
  
        } else if (Tok.is(tok::l_square)) {
          if (CheckProhibitedCXX11Attribute())
            return ExprError();
  
          // offsetof-member-designator: offsetof-member-design '[' expression ']'
          Comps.push_back(Sema::OffsetOfComponent());
          Comps.back().isBrackets = true;
          BalancedDelimiterTracker ST(*this, tok::l_square);
          ST.consumeOpen();
          Comps.back().LocStart = ST.getOpenLocation();
          Res = ParseExpression();
          if (Res.isInvalid()) {
            SkipUntil(tok::r_paren, StopAtSemi);
            return Res;
          }
          Comps.back().U.E = Res.get();
  
          ST.consumeClose();
          Comps.back().LocEnd = ST.getCloseLocation();
        } else {
          if (Tok.isNot(tok::r_paren)) {
            PT.consumeClose();
            Res = ExprError();
          } else if (Ty.isInvalid()) {
            Res = ExprError();
          } else {
            PT.consumeClose();
            Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc,
                                               Ty.get(), Comps,
                                               PT.getCloseLocation());
          }
          break;
        }
      }
      break;
    }
    case tok::kw___builtin_choose_expr: {
      ExprResult Cond(ParseAssignmentExpression());
      if (Cond.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return Cond;
      }
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      ExprResult Expr1(ParseAssignmentExpression());
      if (Expr1.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return Expr1;
      }
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      ExprResult Expr2(ParseAssignmentExpression());
      if (Expr2.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return Expr2;
      }
      if (Tok.isNot(tok::r_paren)) {
        Diag(Tok, diag::err_expected) << tok::r_paren;
        return ExprError();
      }
      Res = Actions.ActOnChooseExpr(StartLoc, Cond.get(), Expr1.get(),
                                    Expr2.get(), ConsumeParen());
      break;
    }
    case tok::kw___builtin_astype: {
      // The first argument is an expression to be converted, followed by a comma.
      ExprResult Expr(ParseAssignmentExpression());
      if (Expr.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      // Second argument is the type to bitcast to.
      TypeResult DestTy = ParseTypeName();
      if (DestTy.isInvalid())
        return ExprError();
  
      // Attempt to consume the r-paren.
      if (Tok.isNot(tok::r_paren)) {
        Diag(Tok, diag::err_expected) << tok::r_paren;
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      Res = Actions.ActOnAsTypeExpr(Expr.get(), DestTy.get(), StartLoc,
                                    ConsumeParen());
      break;
    }
    case tok::kw___builtin_convertvector: {
      // The first argument is an expression to be converted, followed by a comma.
      ExprResult Expr(ParseAssignmentExpression());
      if (Expr.isInvalid()) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      if (ExpectAndConsume(tok::comma)) {
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      // Second argument is the type to bitcast to.
      TypeResult DestTy = ParseTypeName();
      if (DestTy.isInvalid())
        return ExprError();
  
      // Attempt to consume the r-paren.
      if (Tok.isNot(tok::r_paren)) {
        Diag(Tok, diag::err_expected) << tok::r_paren;
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
  
      Res = Actions.ActOnConvertVectorExpr(Expr.get(), DestTy.get(), StartLoc,
                                           ConsumeParen());
      break;
    }
    case tok::kw___builtin_COLUMN:
    case tok::kw___builtin_FILE:
    case tok::kw___builtin_FUNCTION:
    case tok::kw___builtin_LINE: {
      // Attempt to consume the r-paren.
      if (Tok.isNot(tok::r_paren)) {
        Diag(Tok, diag::err_expected) << tok::r_paren;
        SkipUntil(tok::r_paren, StopAtSemi);
        return ExprError();
      }
      SourceLocExpr::IdentKind Kind = [&] {
        switch (T) {
        case tok::kw___builtin_FILE:
          return SourceLocExpr::File;
        case tok::kw___builtin_FUNCTION:
          return SourceLocExpr::Function;
        case tok::kw___builtin_LINE:
          return SourceLocExpr::Line;
        case tok::kw___builtin_COLUMN:
          return SourceLocExpr::Column;
        default:
          llvm_unreachable("invalid keyword");
        }
      }();
      Res = Actions.ActOnSourceLocExpr(Kind, StartLoc, ConsumeParen());
      break;
    }
    }
  
    if (Res.isInvalid())
      return ExprError();
  
    // These can be followed by postfix-expr pieces because they are
    // primary-expressions.
    return ParsePostfixExpressionSuffix(Res.get());
  }
  
  bool Parser::tryParseOpenMPArrayShapingCastPart() {
    assert(Tok.is(tok::l_square) && "Expected open bracket");
    bool ErrorFound = true;
    TentativeParsingAction TPA(*this);
    do {
      if (Tok.isNot(tok::l_square))
        break;
      // Consume '['
      ConsumeBracket();
      // Skip inner expression.
      while (!SkipUntil(tok::r_square, tok::annot_pragma_openmp_end,
                        StopAtSemi | StopBeforeMatch))
        ;
      if (Tok.isNot(tok::r_square))
        break;
      // Consume ']'
      ConsumeBracket();
      // Found ')' - done.
      if (Tok.is(tok::r_paren)) {
        ErrorFound = false;
        break;
      }
    } while (Tok.isNot(tok::annot_pragma_openmp_end));
    TPA.Revert();
    return !ErrorFound;
  }
  
  /// ParseParenExpression - This parses the unit that starts with a '(' token,
  /// based on what is allowed by ExprType.  The actual thing parsed is returned
  /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type,
  /// not the parsed cast-expression.
  ///
  /// \verbatim
  ///       primary-expression: [C99 6.5.1]
  ///         '(' expression ')'
  /// [GNU]   '(' compound-statement ')'      (if !ParenExprOnly)
  ///       postfix-expression: [C99 6.5.2]
  ///         '(' type-name ')' '{' initializer-list '}'
  ///         '(' type-name ')' '{' initializer-list ',' '}'
  ///       cast-expression: [C99 6.5.4]
  ///         '(' type-name ')' cast-expression
  /// [ARC]   bridged-cast-expression
  /// [ARC] bridged-cast-expression:
  ///         (__bridge type-name) cast-expression
  ///         (__bridge_transfer type-name) cast-expression
  ///         (__bridge_retained type-name) cast-expression
  ///       fold-expression: [C++1z]
  ///         '(' cast-expression fold-operator '...' ')'
  ///         '(' '...' fold-operator cast-expression ')'
  ///         '(' cast-expression fold-operator '...'
  ///                 fold-operator cast-expression ')'
  /// [OPENMP] Array shaping operation
  ///       '(' '[' expression ']' { '[' expression ']' } cast-expression
  /// \endverbatim
  ExprResult
  Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
                               bool isTypeCast, ParsedType &CastTy,
                               SourceLocation &RParenLoc) {
    assert(Tok.is(tok::l_paren) && "Not a paren expr!");
    ColonProtectionRAIIObject ColonProtection(*this, false);
    BalancedDelimiterTracker T(*this, tok::l_paren);
    if (T.consumeOpen())
      return ExprError();
    SourceLocation OpenLoc = T.getOpenLocation();
  
    PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc);
  
    ExprResult Result(true);
    bool isAmbiguousTypeId;
    CastTy = nullptr;
  
    if (Tok.is(tok::code_completion)) {
      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);
  
      checkCompoundToken(OpenLoc, tok::l_paren, CompoundToken::StmtExprBegin);
  
      if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) {
        Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope));
      } else {
        // Find the nearest non-record decl context. Variables declared in a
        // statement expression behave as if they were declared in the enclosing
        // function, block, or other code construct.
        DeclContext *CodeDC = Actions.CurContext;
        while (CodeDC->isRecord() || isa<EnumDecl>(CodeDC)) {
          CodeDC = CodeDC->getParent();
          assert(CodeDC && !CodeDC->isFileContext() &&
                 "statement expr not in code context");
        }
        Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false);
  
        Actions.ActOnStartStmtExpr();
  
        StmtResult Stmt(ParseCompoundStatement(true));
        ExprType = CompoundStmt;
  
        // If the substmt parsed correctly, build the AST node.
        if (!Stmt.isInvalid()) {
          Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(),
                                         Tok.getLocation());
        } else {
          Actions.ActOnStmtExprError();
        }
      }
    } else if (ExprType >= CompoundLiteral && BridgeCast) {
      tok::TokenKind tokenKind = Tok.getKind();
      SourceLocation BridgeKeywordLoc = ConsumeToken();
  
      // Parse an Objective-C ARC ownership cast expression.
      ObjCBridgeCastKind Kind;
      if (tokenKind == tok::kw___bridge)
        Kind = OBC_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::TypeName);
      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 if (getLangOpts().OpenMP >= 50 && OpenMPDirectiveParsing &&
               ExprType == CastExpr && Tok.is(tok::l_square) &&
               tryParseOpenMPArrayShapingCastPart()) {
      bool ErrorFound = false;
      SmallVector<Expr *, 4> OMPDimensions;
      SmallVector<SourceRange, 4> OMPBracketsRanges;
      do {
        BalancedDelimiterTracker TS(*this, tok::l_square);
        TS.consumeOpen();
        ExprResult NumElements =
            Actions.CorrectDelayedTyposInExpr(ParseExpression());
        if (!NumElements.isUsable()) {
          ErrorFound = true;
          while (!SkipUntil(tok::r_square, tok::r_paren,
                            StopAtSemi | StopBeforeMatch))
            ;
        }
        TS.consumeClose();
        OMPDimensions.push_back(NumElements.get());
        OMPBracketsRanges.push_back(TS.getRange());
      } while (Tok.isNot(tok::r_paren));
      // Match the ')'.
      T.consumeClose();
      RParenLoc = T.getCloseLocation();
      Result = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
      if (ErrorFound) {
        Result = ExprError();
      } else if (!Result.isInvalid()) {
        Result = Actions.ActOnOMPArrayShapingExpr(
            Result.get(), OpenLoc, RParenLoc, OMPDimensions, OMPBracketsRanges);
      }
      return Result;
    } 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);
    PreferredType.enterTypeCast(Tok.getLocation(), Ty.get());
    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(getCurScope(), 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());
      else if (Tok.is(tok::code_completion)) {
        // There's nothing to suggest in here as we parsed a full expression.
        // Instead fail and propogate the error since caller might have something
        // the suggest, e.g. signature help in function call. Note that this is
        // performed before pushing the \p Expr, so that signature help can report
        // current argument correctly.
        SawError = true;
        cutOffParsing();
        break;
      }
      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::BlockLiteral);
    DeclaratorInfo.setFunctionDefinitionKind(FunctionDefinitionKind::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::BlockLiteral);
    ParamInfo.setFunctionDefinitionKind(FunctionDefinitionKind::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());
  }
  