diff options
| author | 2020-08-03 15:06:44 +0000 | |
|---|---|---|
| committer | 2020-08-03 15:06:44 +0000 | |
| commit | b64793999546ed8adebaeebd9d8345d18db8927d (patch) | |
| tree | 4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp | |
| parent | Add support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff) | |
| download | wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip | |
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp | 3180 |
1 files changed, 0 insertions, 3180 deletions
diff --git a/gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp deleted file mode 100644 index 4bcbebcbb48..00000000000 --- a/gnu/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ /dev/null @@ -1,3180 +0,0 @@ -//===--- ParseExpr.cpp - Expression Parsing -------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \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/Basic/PrettyStackTrace.h" -#include "clang/Parse/RAIIObjectsForParser.h" -#include "clang/Sema/DeclSpec.h" -#include "clang/Sema/ParsedTemplate.h" -#include "clang/Sema/Scope.h" -#include "clang/Sema/TypoCorrection.h" -#include "llvm/ADT/SmallVector.h" -using namespace clang; - -/// Simple precedence-based parser for binary/ternary operators. -/// -/// Note: we diverge from the C99 grammar when parsing the assignment-expression -/// production. C99 specifies that the LHS of an assignment operator should be -/// parsed as a unary-expression, but consistency dictates that it be a -/// conditional-expession. In practice, the important thing here is that the -/// LHS of an assignment has to be an l-value, which productions between -/// unary-expression and conditional-expression don't produce. Because we want -/// consistency, we parse the LHS as a conditional-expression, then check for -/// l-value-ness in semantic analysis stages. -/// -/// \verbatim -/// pm-expression: [C++ 5.5] -/// cast-expression -/// pm-expression '.*' cast-expression -/// pm-expression '->*' cast-expression -/// -/// multiplicative-expression: [C99 6.5.5] -/// Note: in C++, apply pm-expression instead of cast-expression -/// cast-expression -/// multiplicative-expression '*' cast-expression -/// multiplicative-expression '/' cast-expression -/// multiplicative-expression '%' cast-expression -/// -/// additive-expression: [C99 6.5.6] -/// multiplicative-expression -/// additive-expression '+' multiplicative-expression -/// additive-expression '-' multiplicative-expression -/// -/// shift-expression: [C99 6.5.7] -/// additive-expression -/// shift-expression '<<' additive-expression -/// shift-expression '>>' additive-expression -/// -/// compare-expression: [C++20 expr.spaceship] -/// shift-expression -/// compare-expression '<=>' shift-expression -/// -/// relational-expression: [C99 6.5.8] -/// compare-expression -/// relational-expression '<' compare-expression -/// relational-expression '>' compare-expression -/// relational-expression '<=' compare-expression -/// relational-expression '>=' compare-expression -/// -/// equality-expression: [C99 6.5.9] -/// relational-expression -/// equality-expression '==' relational-expression -/// equality-expression '!=' relational-expression -/// -/// AND-expression: [C99 6.5.10] -/// equality-expression -/// AND-expression '&' equality-expression -/// -/// exclusive-OR-expression: [C99 6.5.11] -/// AND-expression -/// exclusive-OR-expression '^' AND-expression -/// -/// inclusive-OR-expression: [C99 6.5.12] -/// exclusive-OR-expression -/// inclusive-OR-expression '|' exclusive-OR-expression -/// -/// logical-AND-expression: [C99 6.5.13] -/// inclusive-OR-expression -/// logical-AND-expression '&&' inclusive-OR-expression -/// -/// logical-OR-expression: [C99 6.5.14] -/// logical-AND-expression -/// logical-OR-expression '||' logical-AND-expression -/// -/// conditional-expression: [C99 6.5.15] -/// logical-OR-expression -/// logical-OR-expression '?' expression ':' conditional-expression -/// [GNU] logical-OR-expression '?' ':' conditional-expression -/// [C++] the third operand is an assignment-expression -/// -/// assignment-expression: [C99 6.5.16] -/// conditional-expression -/// unary-expression assignment-operator assignment-expression -/// [C++] throw-expression [C++ 15] -/// -/// assignment-operator: one of -/// = *= /= %= += -= <<= >>= &= ^= |= -/// -/// expression: [C99 6.5.17] -/// assignment-expression ...[opt] -/// expression ',' assignment-expression ...[opt] -/// \endverbatim -ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { - ExprResult LHS(ParseAssignmentExpression(isTypeCast)); - return ParseRHSOfBinaryExpression(LHS, prec::Comma); -} - -/// This routine is called when the '@' is seen and consumed. -/// Current token is an Identifier and is not a 'try'. This -/// routine is necessary to disambiguate \@try-statement from, -/// for example, \@encode-expression. -/// -ExprResult -Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { - ExprResult LHS(ParseObjCAtExpression(AtLoc)); - return ParseRHSOfBinaryExpression(LHS, prec::Comma); -} - -/// This routine is called when a leading '__extension__' is seen and -/// consumed. This is necessary because the token gets consumed in the -/// process of disambiguating between an expression and a declaration. -ExprResult -Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { - ExprResult LHS(true); - { - // Silence extension warnings in the sub-expression - ExtensionRAIIObject O(Diags); - - LHS = ParseCastExpression(false); - } - - 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.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - cutOffParsing(); - return ExprError(); - } - - if (Tok.is(tok::kw_throw)) - return ParseThrowExpression(); - if (Tok.is(tok::kw_co_yield)) - return ParseCoyieldExpression(); - - ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, - /*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(false, 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(false, false, NotTypeCast)); - ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); - return Actions.ActOnCaseExpr(CaseLoc, Res); -} - -/// Parse a constraint-expression. -/// -/// \verbatim -/// constraint-expression: [Concepts TS temp.constr.decl p1] -/// logical-or-expression -/// \endverbatim -ExprResult Parser::ParseConstraintExpression() { - // FIXME: this may erroneously consume a function-body as the braced - // initializer list of a compound literal - // - // FIXME: this may erroneously consume a parenthesized rvalue reference - // declarator as a parenthesized address-of-label expression - ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); - ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); - - return Res; -} - -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; - - while (1) { - // If this token has a lower precedence than we are allowed to parse (e.g. - // because we are called recursively, or because the token is not a binop), - // then we are done! - if (NextTokPrec < MinPrec) - return 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); - 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); - 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); - 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(); - } - } - - // Code completion for the right-hand side of a binary expression goes - // through a special hook that takes the left-hand side into account. - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteBinaryRHS(getCurScope(), LHS.get(), - OpToken.getKind()); - cutOffParsing(); - return ExprError(); - } - - // 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(false); - - if (RHS.isInvalid()) { - // FIXME: Errors generated by the delayed typo correction should be - // printed before errors from parsing the RHS, not after. - Actions.CorrectDelayedTyposInExpr(LHS); - if (TernaryMiddle.isUsable()) - TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); - LHS = ExprError(); - } - - // Remember the precedence of this operator and get the precedence of the - // operator immediately to the right of the RHS. - prec::Level ThisPrec = NextTokPrec; - NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, - getLangOpts().CPlusPlus11); - - // Assignment and conditional expressions are right-associative. - bool isRightAssoc = ThisPrec == prec::Conditional || - ThisPrec == prec::Assignment; - - // Get the precedence of the operator to the right of the RHS. If it binds - // more tightly with RHS than we do, evaluate it completely first. - if (ThisPrec < NextTokPrec || - (ThisPrec == NextTokPrec && isRightAssoc)) { - if (!RHS.isInvalid() && RHSIsInitList) { - Diag(Tok, diag::err_init_list_bin_op) - << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); - RHS = ExprError(); - } - // If this is left-associative, only parse things on the RHS that bind - // more tightly than the current operator. If it is left-associative, it - // is okay, to bind exactly as tightly. For example, compile A=B=C=D as - // A=(B=(C=D)), where each paren is a level of recursion here. - // The function takes ownership of the RHS. - RHS = ParseRHSOfBinaryExpression(RHS, - static_cast<prec::Level>(ThisPrec + !isRightAssoc)); - RHSIsInitList = false; - - if (RHS.isInvalid()) { - // FIXME: Errors generated by the delayed typo correction should be - // printed before errors from ParseRHSOfBinaryExpression, not after. - Actions.CorrectDelayedTyposInExpr(LHS); - if (TernaryMiddle.isUsable()) - TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); - LHS = ExprError(); - } - - NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, - getLangOpts().CPlusPlus11); - } - - if (!RHS.isInvalid() && RHSIsInitList) { - if (ThisPrec == prec::Assignment) { - Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) - << Actions.getExprRange(RHS.get()); - } else if (ColonLoc.isValid()) { - Diag(ColonLoc, diag::err_init_list_bin_op) - << /*RHS*/1 << ":" - << Actions.getExprRange(RHS.get()); - LHS = ExprError(); - } else { - Diag(OpToken, diag::err_init_list_bin_op) - << /*RHS*/1 << PP.getSpelling(OpToken) - << Actions.getExprRange(RHS.get()); - LHS = ExprError(); - } - } - - ExprResult OrigLHS = LHS; - if (!LHS.isInvalid()) { - // Combine the LHS and RHS into the LHS (e.g. build AST). - if (TernaryMiddle.isInvalid()) { - // If we're using '>>' as an operator within a template - // argument list (in C++98), suggest the addition of - // parentheses so that the code remains well-formed in C++0x. - if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater)) - SuggestParentheses(OpToken.getLocation(), - diag::warn_cxx11_right_shift_in_template_arg, - SourceRange(Actions.getExprRange(LHS.get()).getBegin(), - Actions.getExprRange(RHS.get()).getEnd())); - - LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), - OpToken.getKind(), LHS.get(), RHS.get()); - - } else { - LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, - LHS.get(), TernaryMiddle.get(), - RHS.get()); - } - // In this case, ActOnBinOp or ActOnConditionalOp performed the - // CorrectDelayedTyposInExpr check. - if (!getLangOpts().CPlusPlus) - continue; - } - - // Ensure potential typos aren't left undiagnosed. - if (LHS.isInvalid()) { - Actions.CorrectDelayedTyposInExpr(OrigLHS); - Actions.CorrectDelayedTyposInExpr(TernaryMiddle); - Actions.CorrectDelayedTyposInExpr(RHS); - } - } -} - -/// Parse a cast-expression, or, if \p isUnaryExpression 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. -/// -ExprResult Parser::ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand, - TypeCastState isTypeCast, - bool isVectorLiteral) { - bool NotCastExpr; - ExprResult Res = ParseCastExpression(isUnaryExpression, - isAddressOfOperand, - NotCastExpr, - isTypeCast, - isVectorLiteral); - if (NotCastExpr) - Diag(Tok, diag::err_expected_expression); - return Res; -} - -namespace { -class CastExpressionIdValidator : 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; - } - - private: - Token NextToken; - bool AllowNonTypes; -}; -} - -/// Parse a cast-expression, or, if \pisUnaryExpression is true, parse -/// a unary-expression. -/// -/// \p isAddressOfOperand exists because an id-expression that is the operand -/// of address-of gets special treatment due to member pointers. NotCastExpr -/// is set to true if the token is not the start of a cast-expression, and no -/// diagnostic is emitted in this case and no tokens are consumed. -/// -/// \verbatim -/// cast-expression: [C99 6.5.4] -/// unary-expression -/// '(' type-name ')' cast-expression -/// -/// unary-expression: [C99 6.5.3] -/// postfix-expression -/// '++' unary-expression -/// '--' unary-expression -/// [Coro] 'co_await' cast-expression -/// unary-operator cast-expression -/// 'sizeof' unary-expression -/// 'sizeof' '(' type-name ')' -/// [C++11] 'sizeof' '...' '(' identifier ')' -/// [GNU] '__alignof' unary-expression -/// [GNU] '__alignof' '(' type-name ')' -/// [C11] '_Alignof' '(' type-name ')' -/// [C++11] 'alignof' '(' type-id ')' -/// [GNU] '&&' identifier -/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] -/// [C++] new-expression -/// [C++] delete-expression -/// -/// unary-operator: one of -/// '&' '*' '+' '-' '~' '!' -/// [GNU] '__extension__' '__real' '__imag' -/// -/// primary-expression: [C99 6.5.1] -/// [C99] identifier -/// [C++] id-expression -/// constant -/// string-literal -/// [C++] boolean-literal [C++ 2.13.5] -/// [C++11] 'nullptr' [C++11 2.14.7] -/// [C++11] user-defined-literal -/// '(' expression ')' -/// [C11] generic-selection -/// '__func__' [C99 6.4.2.2] -/// [GNU] '__FUNCTION__' -/// [MS] '__FUNCDNAME__' -/// [MS] 'L__FUNCTION__' -/// [MS] '__FUNCSIG__' -/// [MS] 'L__FUNCSIG__' -/// [GNU] '__PRETTY_FUNCTION__' -/// [GNU] '(' compound-statement ')' -/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' -/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' -/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' -/// assign-expr ')' -/// [GNU] '__builtin_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(bool isUnaryExpression, - bool isAddressOfOperand, - bool &NotCastExpr, - TypeCastState isTypeCast, - bool isVectorLiteral) { - ExprResult Res; - tok::TokenKind SavedKind = Tok.getKind(); - NotCastExpr = false; - - // This handles all of cast-expression, unary-expression, postfix-expression, - // and primary-expression. We handle them together like this for efficiency - // and to simplify handling of an expression starting with a '(' token: which - // may be one of a parenthesized expression, cast-expression, compound literal - // expression, or statement expression. - // - // If the parsed tokens consist of a primary-expression, the cases below - // break out of the switch; at the end we call ParsePostfixExpressionSuffix - // to handle the postfix expression suffixes. Cases that cannot be followed - // by postfix exprs should return without invoking - // ParsePostfixExpressionSuffix. - switch (SavedKind) { - case tok::l_paren: { - // If this expression is limited to being a unary-expression, the parent can - // not start a cast expression. - ParenParseOption ParenExprType = - (isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral - : CastExpr; - ParsedType CastTy; - SourceLocation RParenLoc; - Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - isTypeCast == IsTypeCast, CastTy, RParenLoc); - - if (isVectorLiteral) - return Res; - - switch (ParenExprType) { - case SimpleExpr: break; // Nothing else to do. - case CompoundStmt: break; // Nothing else to do. - case CompoundLiteral: - // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of - // postfix-expression exist, parse them now. - break; - case CastExpr: - // We have parsed the cast-expression and no postfix-expr pieces are - // following. - return Res; - case FoldExpr: - // We only parsed a fold-expression. There might be postfix-expr pieces - // afterwards; parse them now. - break; - } - - break; - } - - // primary-expression - case tok::numeric_constant: - // constant: integer-constant - // constant: floating-constant - - Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); - ConsumeToken(); - break; - - case tok::kw_true: - case tok::kw_false: - Res = ParseCXXBoolLiteral(); - break; - - case tok::kw___objc_yes: - case tok::kw___objc_no: - return ParseObjCBoolLiteral(); - - case tok::kw_nullptr: - Diag(Tok, diag::warn_cxx98_compat_nullptr); - return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); - - case tok::annot_primary_expr: - assert(Res.get() == nullptr && "Stray primary-expression annotation?"); - Res = getExprAnnotation(Tok); - ConsumeAnnotationToken(); - if (!Res.isInvalid() && Tok.is(tok::less)) - checkPotentialAngleBracket(Res); - 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(isUnaryExpression, isAddressOfOperand); - - 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(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } - } - - 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(isUnaryExpression, isAddressOfOperand); - } - } - - // Consume the identifier so that we can see if it is followed by a '(' or - // '.'. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation ILoc = ConsumeToken(); - - // Support 'Class.property' and 'super.property' notation. - if (getLangOpts().ObjC && Tok.is(tok::period) && - (Actions.getTypeName(II, ILoc, getCurScope()) || - // Allow the base to be 'super' if in an objc-method. - (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { - ConsumeToken(); - - if (Tok.is(tok::code_completion) && &II != Ident_super) { - Actions.CodeCompleteObjCClassPropertyRefExpr( - getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); - cutOffParsing(); - return ExprError(); - } - // Allow either an identifier or the keyword 'class' (in C++). - if (Tok.isNot(tok::identifier) && - !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { - Diag(Tok, diag::err_expected_property_name); - return ExprError(); - } - IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); - SourceLocation PropertyLoc = ConsumeToken(); - - Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, - ILoc, PropertyLoc); - break; - } - - // In an Objective-C method, if we have "super" followed by an identifier, - // the token sequence is ill-formed. However, if there's a ':' or ']' after - // that identifier, this is probably a message send with a missing open - // bracket. Treat it as such. - if (getLangOpts().ObjC && &II == Ident_super && !InMessageExpression && - getCurScope()->isInObjcMethodScope() && - ((Tok.is(tok::identifier) && - (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || - Tok.is(tok::code_completion))) { - Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, - nullptr); - break; - } - - // If we have an Objective-C class name followed by an identifier - // and either ':' or ']', this is an Objective-C class message - // send that's missing the opening '['. Recovery - // appropriately. Also take this path if we're performing code - // completion after an Objective-C class name. - if (getLangOpts().ObjC && - ((Tok.is(tok::identifier) && !InMessageExpression) || - Tok.is(tok::code_completion))) { - const Token& Next = NextToken(); - if (Tok.is(tok::code_completion) || - Next.is(tok::colon) || Next.is(tok::r_square)) - if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) - if (Typ.get()->isObjCObjectOrInterfaceType()) { - // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS(AttrFactory); - DS.SetRangeStart(ILoc); - DS.SetRangeEnd(ILoc); - const char *PrevSpec = nullptr; - unsigned DiagID; - DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ, - Actions.getASTContext().getPrintingPolicy()); - - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); - TypeResult Ty = Actions.ActOnTypeName(getCurScope(), - DeclaratorInfo); - if (Ty.isInvalid()) - break; - - Res = ParseObjCMessageExpressionBody(SourceLocation(), - SourceLocation(), - Ty.get(), nullptr); - break; - } - } - - // Make sure to pass down the right value for isAddressOfOperand. - if (isAddressOfOperand && isPostfixExpressionSuffixStart()) - isAddressOfOperand = false; - - // Function designators are allowed to be undeclared (C99 6.5.1p2), so we - // need to know whether or not this identifier is a function designator or - // not. - UnqualifiedId Name; - CXXScopeSpec ScopeSpec; - SourceLocation TemplateKWLoc; - Token Replacement; - auto Validator = llvm::make_unique<CastExpressionIdValidator>( - Tok, isTypeCast != NotTypeCast, 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, std::move(Validator), - /*IsInlineAsmIdentifier=*/false, - Tok.is(tok::r_paren) ? nullptr : &Replacement); - if (!Res.isInvalid() && Res.isUnset()) { - UnconsumeToken(Replacement); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } - if (!Res.isInvalid() && Tok.is(tok::less)) - checkPotentialAngleBracket(Res); - break; - } - case tok::char_constant: // constant: character-constant - case tok::wide_char_constant: - case tok::utf8_char_constant: - case tok::utf16_char_constant: - case tok::utf32_char_constant: - Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); - ConsumeToken(); - break; - case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] - case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] - case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS] - case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS] - case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] - case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] - case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] - Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); - ConsumeToken(); - break; - case tok::string_literal: // primary-expression: string-literal - case tok::wide_string_literal: - case tok::utf8_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - Res = ParseStringLiteralExpression(true); - break; - case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] - Res = ParseGenericSelectionExpression(); - break; - case tok::kw___builtin_available: - return ParseAvailabilityCheckExpr(Tok.getLocation()); - case tok::kw___builtin_va_arg: - case tok::kw___builtin_offsetof: - case tok::kw___builtin_choose_expr: - case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() - case tok::kw___builtin_convertvector: - return ParseBuiltinPrimaryExpression(); - case tok::kw___null: - return Actions.ActOnGNUNullExpr(ConsumeToken()); - - case tok::plusplus: // unary-expression: '++' unary-expression [C99] - case tok::minusminus: { // unary-expression: '--' unary-expression [C99] - // C++ [expr.unary] has: - // unary-expression: - // ++ cast-expression - // -- cast-expression - Token SavedTok = Tok; - ConsumeToken(); - // 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, - /*isAddressOfOperand*/false, NotCastExpr, - NotTypeCast); - if (NotCastExpr) { - // If we return with NotCastExpr = true, we must not consume any tokens, - // so put the token back where we found it. - assert(Res.isInvalid()); - UnconsumeToken(SavedTok); - return ExprError(); - } - if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), - SavedKind, Res.get()); - return Res; - } - case tok::amp: { // unary-expression: '&' cast-expression - // Special treatment because of member pointers - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false, true); - if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return Res; - } - - case tok::star: // unary-expression: '*' cast-expression - case tok::plus: // unary-expression: '+' cast-expression - case tok::minus: // unary-expression: '-' cast-expression - case tok::tilde: // unary-expression: '~' cast-expression - case tok::exclaim: // unary-expression: '!' cast-expression - case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] - case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); - if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return Res; - } - - case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression - SourceLocation CoawaitLoc = ConsumeToken(); - Res = ParseCastExpression(false); - 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. - ExtensionRAIIObject O(Diags); // Use RAII to do this. - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); - 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_alignment) << 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: - return ParseUnaryExprOrTypeTraitExpression(); - case tok::ampamp: { // unary-expression: '&&' identifier - SourceLocation AmpAmpLoc = ConsumeToken(); - if (Tok.isNot(tok::identifier)) - return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); - - if (getCurScope()->getFnParent() == nullptr) - return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); - - Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); - LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), - Tok.getLocation()); - Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); - ConsumeToken(); - return Res; - } - case tok::kw_const_cast: - case tok::kw_dynamic_cast: - case tok::kw_reinterpret_cast: - case tok::kw_static_cast: - Res = ParseCXXCasts(); - break; - case tok::kw_typeid: - Res = ParseCXXTypeid(); - break; - case tok::kw___uuidof: - Res = ParseCXXUuidof(); - break; - case tok::kw_this: - Res = ParseCXXThis(); - break; - - case tok::annot_typename: - if (isStartOfObjCClassMessageMissingOpenBracket()) { - ParsedType Type = getTypeAnnotation(Tok); - - // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS(AttrFactory); - DS.SetRangeStart(Tok.getLocation()); - DS.SetRangeEnd(Tok.getLastLoc()); - - const char *PrevSpec = nullptr; - unsigned DiagID; - DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), - PrevSpec, DiagID, Type, - Actions.getASTContext().getPrintingPolicy()); - - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); - TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); - if (Ty.isInvalid()) - break; - - ConsumeAnnotationToken(); - Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - Ty.get(), nullptr); - break; - } - LLVM_FALLTHROUGH; - - case tok::annot_decltype: - case tok::kw_char: - case tok::kw_wchar_t: - case tok::kw_char8_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_half: - case tok::kw_float: - case tok::kw_double: - case tok::kw__Float16: - case tok::kw___float128: - case tok::kw_void: - case tok::kw_typename: - case tok::kw_typeof: - case tok::kw___vector: -#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: -#include "clang/Basic/OpenCLImageTypes.def" - { - if (!getLangOpts().CPlusPlus) { - Diag(Tok, diag::err_expected_expression); - return ExprError(); - } - - 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(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - - Token Next = NextToken(); - if (Next.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); - if (TemplateId->Kind == TNK_Type_template) { - // We have a qualified template-id that we know refers to a - // type, translate it into a type and continue parsing as a - // cast expression. - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, nullptr, - /*EnteringContext=*/false); - AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } - } - - // 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. - AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } - - // 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(isUnaryExpression, isAddressOfOperand); - - // ::new -> [C++] new-expression - // ::delete -> [C++] delete-expression - SourceLocation CCLoc = ConsumeToken(); - if (Tok.is(tok::kw_new)) - return ParseCXXNewExpression(true, CCLoc); - if (Tok.is(tok::kw_delete)) - return ParseCXXDeleteExpression(true, CCLoc); - - // This is not a type name or scope specifier, it is an invalid expression. - Diag(CCLoc, diag::err_expected_expression); - return ExprError(); - } - - case tok::kw_new: // [C++] new-expression - return ParseCXXNewExpression(false, Tok.getLocation()); - - case tok::kw_delete: // [C++] delete-expression - return ParseCXXDeleteExpression(false, Tok.getLocation()); - - case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' - Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); - SourceLocation KeyLoc = ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - - if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) - return ExprError(); - // C++11 [expr.unary.noexcept]p1: - // The noexcept operator determines whether the evaluation of its operand, - // which is an unevaluated operand, can throw an exception. - EnterExpressionEvaluationContext Unevaluated( - Actions, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult Result = ParseExpression(); - - T.consumeClose(); - - if (!Result.isInvalid()) - Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), - Result.get(), T.getCloseLocation()); - return Result; - } - -#define TYPE_TRAIT(N,Spelling,K) \ - case tok::kw_##Spelling: -#include "clang/Basic/TokenKinds.def" - return ParseTypeTrait(); - - case tok::kw___array_rank: - case tok::kw___array_extent: - return ParseArrayTypeTrait(); - - case tok::kw___is_lvalue_expr: - case tok::kw___is_rvalue_expr: - return ParseExpressionTrait(); - - case tok::at: { - SourceLocation AtLoc = ConsumeToken(); - return ParseObjCAtExpression(AtLoc); - } - case tok::caret: - Res = ParseBlockLiteralExpression(); - break; - case tok::code_completion: { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - cutOffParsing(); - return ExprError(); - } - case tok::l_square: - if (getLangOpts().CPlusPlus11) { - if (getLangOpts().ObjC) { - // C++11 lambda expressions and Objective-C message sends both start with a - // square bracket. There are three possibilities here: - // we have a valid lambda expression, we have an invalid lambda - // expression, or we have something that doesn't appear to be a lambda. - // If we're in the last case, we fall back to ParseObjCMessageExpression. - Res = TryParseLambdaExpression(); - if (!Res.isInvalid() && !Res.get()) - 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. - - // These can be followed by postfix-expr pieces. - 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; - while (1) { - switch (Tok.getKind()) { - case tok::code_completion: - if (InMessageExpression) - return LHS; - - Actions.CodeCompletePostfixExpression(getCurScope(), LHS); - cutOffParsing(); - return ExprError(); - - case tok::identifier: - // If we see identifier: after an expression, and we're not already in a - // message send, then this is probably a message send with a missing - // opening bracket '['. - if (getLangOpts().ObjC && !InMessageExpression && - (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { - LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - nullptr, LHS.get()); - break; - } - // Fall through; this isn't a message send. - LLVM_FALLTHROUGH; - - default: // Not a postfix-expression suffix. - return LHS; - case tok::l_square: { // postfix-expression: p-e '[' expression ']' - // If we have a array postfix expression that starts on a new line and - // Objective-C is enabled, it is highly likely that the user forgot a - // semicolon after the base expression and that the array postfix-expr is - // actually another message send. In this case, do some look-ahead to see - // if the contents of the square brackets are obviously not a valid - // expression and recover by pretending there is no suffix. - if (getLangOpts().ObjC && Tok.isAtStartOfLine() && - isSimpleObjCMessageExpression()) - return LHS; - - // Reject array indices starting with a lambda-expression. '[[' is - // reserved for attributes. - if (CheckProhibitedCXX11Attribute()) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); - return ExprError(); - } - - BalancedDelimiterTracker T(*this, tok::l_square); - T.consumeOpen(); - Loc = T.getOpenLocation(); - ExprResult Idx, Length; - SourceLocation ColonLoc; - if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { - Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); - Idx = ParseBraceInitializer(); - } else if (getLangOpts().OpenMP) { - ColonProtectionRAIIObject RAII(*this); - // Parse [: or [ expr or [ expr : - if (!Tok.is(tok::colon)) { - // [ expr - Idx = ParseExpression(); - } - if (Tok.is(tok::colon)) { - // Consume ':' - ColonLoc = ConsumeToken(); - if (Tok.isNot(tok::r_square)) - Length = ParseExpression(); - } - } else - Idx = ParseExpression(); - - SourceLocation RLoc = Tok.getLocation(); - - ExprResult OrigLHS = LHS; - if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && - Tok.is(tok::r_square)) { - if (ColonLoc.isValid()) { - LHS = Actions.ActOnOMPArraySectionExpr(LHS.get(), Loc, Idx.get(), - ColonLoc, Length.get(), RLoc); - } else { - LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, - Idx.get(), RLoc); - } - } else { - LHS = ExprError(); - } - if (LHS.isInvalid()) { - (void)Actions.CorrectDelayedTyposInExpr(OrigLHS); - (void)Actions.CorrectDelayedTyposInExpr(Idx); - (void)Actions.CorrectDelayedTyposInExpr(Length); - 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; - - if (Tok.is(tok::code_completion)) { - QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), None, PT.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - cutOffParsing(); - return ExprError(); - } - - if (OpKind == tok::l_paren || !LHS.isInvalid()) { - if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - })) { - (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) { - Actions.ProduceCallSignatureHelp(getCurScope(), LHS.get(), - ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - } - LHS = ExprError(); - } else if (LHS.isInvalid()) { - for (auto &E : ArgExprs) - Actions.CorrectDelayedTyposInExpr(E); - } - } - } - - // Match the ')'. - if (LHS.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - } else if (Tok.isNot(tok::r_paren)) { - bool HadDelayedTypo = false; - if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get()) - HadDelayedTypo = true; - for (auto &E : ArgExprs) - if (Actions.CorrectDelayedTyposInExpr(E).get() != E) - HadDelayedTypo = true; - // If there were delayed typos in the LHS or ArgExprs, call SkipUntil - // instead of PT.consumeClose() to avoid emitting extra diagnostics for - // the unmatched l_paren. - if (HadDelayedTypo) - SkipUntil(tok::r_paren, StopAtSemi); - else - PT.consumeClose(); - LHS = ExprError(); - } else { - assert((ArgExprs.size() == 0 || - ArgExprs.size()-1 == CommaLocs.size())&& - "Unexpected number of commas!"); - LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc, - ArgExprs, Tok.getLocation(), - ExecConfig); - PT.consumeClose(); - } - - break; - } - case tok::arrow: - case tok::period: { - // postfix-expression: p-e '->' template[opt] id-expression - // postfix-expression: p-e '.' template[opt] id-expression - tok::TokenKind OpKind = Tok.getKind(); - SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. - - CXXScopeSpec SS; - ParsedType ObjectType; - bool MayBePseudoDestructor = false; - Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; - - if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { - Expr *Base = OrigLHS; - const Type* BaseType = Base->getType().getTypePtrOrNull(); - if (BaseType && Tok.is(tok::l_paren) && - (BaseType->isFunctionType() || - BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) { - Diag(OpLoc, diag::err_function_is_not_record) - << OpKind << Base->getSourceRange() - << FixItHint::CreateRemoval(OpLoc); - return ParsePostfixExpressionSuffix(Base); - } - - LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, - OpLoc, OpKind, ObjectType, - MayBePseudoDestructor); - if (LHS.isInvalid()) - break; - - ParseOptionalCXXScopeSpecifier(SS, ObjectType, - /*EnteringContext=*/false, - &MayBePseudoDestructor); - if (SS.isNotEmpty()) - ObjectType = nullptr; - } - - if (Tok.is(tok::code_completion)) { - tok::TokenKind CorrectedOpKind = - OpKind == tok::arrow ? tok::period : tok::arrow; - ExprResult CorrectedLHS(/*IsInvalid=*/true); - if (getLangOpts().CPlusPlus && OrigLHS) { - const bool DiagsAreSuppressed = Diags.getSuppressAllDiagnostics(); - Diags.setSuppressAllDiagnostics(true); - CorrectedLHS = Actions.ActOnStartCXXMemberReference( - getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType, - MayBePseudoDestructor); - Diags.setSuppressAllDiagnostics(DiagsAreSuppressed); - } - - 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()); - - cutOffParsing(); - return ExprError(); - } - - if (MayBePseudoDestructor && !LHS.isInvalid()) { - LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS, - ObjectType); - break; - } - - // Either the action has told us that this cannot be a - // pseudo-destructor expression (based on the type of base - // expression), or we didn't see a '~' in the right place. We - // can still parse a destructor name here, but in that case it - // names a real destructor. - // Allow explicit constructor calls in Microsoft mode. - // FIXME: Add support for explicit call of template constructor. - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (getLangOpts().ObjC && OpKind == tok::period && - Tok.is(tok::kw_class)) { - // Objective-C++: - // After a '.' in a member access expression, treat the keyword - // 'class' as if it were an identifier. - // - // This hack allows property access to the 'class' method because it is - // such a common method name. For other C++ keywords that are - // Objective-C method names, one must use the message send syntax. - IdentifierInfo *Id = Tok.getIdentifierInfo(); - SourceLocation Loc = ConsumeToken(); - Name.setIdentifier(Id, Loc); - } else if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/ - getLangOpts().MicrosoftExt && - SS.isNotEmpty(), - /*AllowDeductionGuide=*/false, - ObjectType, &TemplateKWLoc, Name)) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); - LHS = ExprError(); - } - - if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, - OpKind, SS, TemplateKWLoc, Name, - CurParsedObjCImpl ? CurParsedObjCImpl->Dcl - : nullptr); - if (!LHS.isInvalid() && Tok.is(tok::less)) - checkPotentialAngleBracket(LHS); - break; - } - case tok::plusplus: // postfix-expression: postfix-expression '++' - case tok::minusminus: // postfix-expression: postfix-expression '--' - if (!LHS.isInvalid()) { - LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), - Tok.getKind(), LHS.get()); - } - ConsumeToken(); - break; - } - } -} - -/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ -/// vec_step and we are at the start of an expression or a parenthesized -/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the -/// expression (isCastExpr == false) or the type (isCastExpr == true). -/// -/// \verbatim -/// unary-expression: [C99 6.5.3] -/// 'sizeof' unary-expression -/// 'sizeof' '(' type-name ')' -/// [GNU] '__alignof' unary-expression -/// [GNU] '__alignof' '(' type-name ')' -/// [C11] '_Alignof' '(' type-name ')' -/// [C++0x] 'alignof' '(' type-id ')' -/// -/// [GNU] typeof-specifier: -/// typeof ( expressions ) -/// typeof ( type-name ) -/// [GNU/C++] typeof unary-expression -/// -/// [OpenCL 1.1 6.11.12] vec_step built-in function: -/// vec_step ( expressions ) -/// vec_step ( type-name ) -/// \endverbatim -ExprResult -Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, - bool &isCastExpr, - ParsedType &CastTy, - SourceRange &CastRange) { - - assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, - tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, - tok::kw___builtin_omp_required_simd_align) && - "Not a typeof/sizeof/alignof/vec_step expression!"); - - ExprResult Operand; - - // If the operand doesn't start with an '(', it must be an expression. - if (Tok.isNot(tok::l_paren)) { - // If construct allows a form without parenthesis, user may forget to put - // pathenthesis around type name. - if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, - tok::kw__Alignof)) { - if (isTypeIdUnambiguously()) { - DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); - ParseDeclarator(DeclaratorInfo); - - SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); - SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation); - Diag(LParenLoc, diag::err_expected_parentheses_around_typename) - << OpTok.getName() - << FixItHint::CreateInsertion(LParenLoc, "(") - << FixItHint::CreateInsertion(RParenLoc, ")"); - isCastExpr = true; - return ExprEmpty(); - } - } - - isCastExpr = false; - if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { - Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo() - << tok::l_paren; - return ExprError(); - } - - Operand = ParseCastExpression(true/*isUnaryExpression*/); - } else { - // If it starts with a '(', we know that it is either a parenthesized - // type-name, or it is a unary-expression that starts with a compound - // literal, or starts with a primary-expression that is a parenthesized - // expression. - ParenParseOption ExprType = CastExpr; - SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - - 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 ')' -/// [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; - } - } - - if (Res.isInvalid()) - return ExprError(); - - // These can be followed by postfix-expr pieces because they are - // primary-expressions. - return ParsePostfixExpressionSuffix(Res.get()); -} - -/// ParseParenExpression - This parses the unit that starts with a '(' token, -/// based on what is allowed by ExprType. The actual thing parsed is returned -/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, -/// not the parsed cast-expression. -/// -/// \verbatim -/// primary-expression: [C99 6.5.1] -/// '(' expression ')' -/// [GNU] '(' compound-statement ')' (if !ParenExprOnly) -/// postfix-expression: [C99 6.5.2] -/// '(' type-name ')' '{' initializer-list '}' -/// '(' type-name ')' '{' initializer-list ',' '}' -/// cast-expression: [C99 6.5.4] -/// '(' type-name ')' cast-expression -/// [ARC] bridged-cast-expression -/// [ARC] bridged-cast-expression: -/// (__bridge type-name) cast-expression -/// (__bridge_transfer type-name) cast-expression -/// (__bridge_retained type-name) cast-expression -/// fold-expression: [C++1z] -/// '(' cast-expression fold-operator '...' ')' -/// '(' '...' fold-operator cast-expression ')' -/// '(' cast-expression fold-operator '...' -/// fold-operator cast-expression ')' -/// \endverbatim -ExprResult -Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool isTypeCast, ParsedType &CastTy, - SourceLocation &RParenLoc) { - assert(Tok.is(tok::l_paren) && "Not a paren expr!"); - ColonProtectionRAIIObject ColonProtection(*this, false); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.consumeOpen()) - return ExprError(); - SourceLocation OpenLoc = T.getOpenLocation(); - - ExprResult Result(true); - bool isAmbiguousTypeId; - CastTy = nullptr; - - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), - ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression - : Sema::PCC_Expression); - cutOffParsing(); - return ExprError(); - } - - // Diagnose use of bridge casts in non-arc mode. - bool BridgeCast = (getLangOpts().ObjC && - Tok.isOneOf(tok::kw___bridge, - tok::kw___bridge_transfer, - tok::kw___bridge_retained, - tok::kw___bridge_retain)); - if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { - if (!TryConsumeToken(tok::kw___bridge)) { - StringRef BridgeCastName = Tok.getName(); - SourceLocation BridgeKeywordLoc = ConsumeToken(); - if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) - Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) - << BridgeCastName - << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); - } - BridgeCast = false; - } - - // None of these cases should fall through with an invalid Result - // unless they've already reported an error. - if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { - Diag(Tok, diag::ext_gnu_statement_expr); - - if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) { - Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope)); - } else { - // Find the nearest non-record decl context. Variables declared in a - // statement expression behave as if they were declared in the enclosing - // function, block, or other code construct. - DeclContext *CodeDC = Actions.CurContext; - while (CodeDC->isRecord() || isa<EnumDecl>(CodeDC)) { - CodeDC = CodeDC->getParent(); - assert(CodeDC && !CodeDC->isFileContext() && - "statement expr not in code context"); - } - Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false); - - Actions.ActOnStartStmtExpr(); - - StmtResult Stmt(ParseCompoundStatement(true)); - ExprType = CompoundStmt; - - // If the substmt parsed correctly, build the AST node. - if (!Stmt.isInvalid()) { - Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation()); - } else { - Actions.ActOnStmtExprError(); - } - } - } else if (ExprType >= CompoundLiteral && BridgeCast) { - tok::TokenKind tokenKind = Tok.getKind(); - SourceLocation BridgeKeywordLoc = ConsumeToken(); - - // Parse an Objective-C ARC ownership cast expression. - ObjCBridgeCastKind Kind; - if (tokenKind == tok::kw___bridge) - Kind = OBC_Bridge; - else if (tokenKind == tok::kw___bridge_transfer) - Kind = OBC_BridgeTransfer; - else if (tokenKind == tok::kw___bridge_retained) - Kind = OBC_BridgeRetained; - else { - // As a hopefully temporary workaround, allow __bridge_retain as - // a synonym for __bridge_retained, but only in system headers. - assert(tokenKind == tok::kw___bridge_retain); - Kind = OBC_BridgeRetained; - if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) - Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain) - << FixItHint::CreateReplacement(BridgeKeywordLoc, - "__bridge_retained"); - } - - TypeResult Ty = ParseTypeName(); - T.consumeClose(); - ColonProtection.restore(); - RParenLoc = T.getCloseLocation(); - ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); - - if (Ty.isInvalid() || SubExpr.isInvalid()) - return ExprError(); - - return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind, - BridgeKeywordLoc, Ty.get(), - RParenLoc, SubExpr.get()); - } else if (ExprType >= CompoundLiteral && - isTypeIdInParens(isAmbiguousTypeId)) { - - // Otherwise, this is a compound literal expression or cast expression. - - // In C++, if the type-id is ambiguous we disambiguate based on context. - // If stopIfCastExpr is true the context is a typeof/sizeof/alignof - // in which case we should treat it as type-id. - // if stopIfCastExpr is false, we need to determine the context past the - // parens, so we defer to ParseCXXAmbiguousParenExpression for that. - if (isAmbiguousTypeId && !stopIfCastExpr) { - ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T, - ColonProtection); - RParenLoc = T.getCloseLocation(); - return res; - } - - // Parse the type declarator. - DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); - ParseDeclarator(DeclaratorInfo); - - // If our type is followed by an identifier and either ':' or ']', then - // this is probably an Objective-C message send where the leading '[' is - // missing. Recover as if that were the case. - if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && - !InMessageExpression && getLangOpts().ObjC && - (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { - TypeResult Ty; - { - InMessageExpressionRAIIObject InMessage(*this, false); - Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); - } - Result = ParseObjCMessageExpressionBody(SourceLocation(), - SourceLocation(), - Ty.get(), nullptr); - } else { - // Match the ')'. - T.consumeClose(); - ColonProtection.restore(); - RParenLoc = T.getCloseLocation(); - if (Tok.is(tok::l_brace)) { - ExprType = CompoundLiteral; - TypeResult Ty; - { - InMessageExpressionRAIIObject InMessage(*this, false); - Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); - } - return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); - } - - if (Tok.is(tok::l_paren)) { - // This could be OpenCL vector Literals - if (getLangOpts().OpenCL) - { - TypeResult Ty; - { - InMessageExpressionRAIIObject InMessage(*this, false); - Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); - } - if(Ty.isInvalid()) - { - return ExprError(); - } - QualType QT = Ty.get().get().getCanonicalType(); - if (QT->isVectorType()) - { - // We parsed '(' vector-type-name ')' followed by '(' - - // Parse the cast-expression that follows it next. - // isVectorLiteral = true will make sure we don't parse any - // Postfix expression yet - Result = ParseCastExpression(/*isUnaryExpression=*/false, - /*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(); - } - - // Parse the cast-expression that follows it next. - // TODO: For cast expression with CastTy. - Result = ParseCastExpression(/*isUnaryExpression=*/false, - /*isAddressOfOperand=*/false, - /*isTypeCast=*/IsTypeCast); - if (!Result.isInvalid()) { - Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, - DeclaratorInfo, CastTy, - RParenLoc, Result.get()); - } - return Result; - } - - Diag(Tok, diag::err_expected_lbrace_in_compound_literal); - return ExprError(); - } - } else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) && - isFoldOperator(NextToken().getKind())) { - ExprType = FoldExpr; - return ParseFoldExpression(ExprResult(), T); - } else if (isTypeCast) { - // Parse the expression-list. - InMessageExpressionRAIIObject InMessage(*this, false); - - ExprVector ArgExprs; - CommaLocsTy CommaLocs; - - if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) { - // FIXME: If we ever support comma expressions as operands to - // fold-expressions, we'll need to allow multiple ArgExprs here. - if (ExprType >= FoldExpr && ArgExprs.size() == 1 && - isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { - ExprType = FoldExpr; - return ParseFoldExpression(ArgExprs[0], T); - } - - ExprType = SimpleExpr; - Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), - ArgExprs); - } - } else { - InMessageExpressionRAIIObject InMessage(*this, false); - - Result = ParseExpression(MaybeTypeCast); - if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) { - // Correct typos in non-C++ code earlier so that implicit-cast-like - // expressions are parsed correctly. - Result = Actions.CorrectDelayedTyposInExpr(Result); - } - - if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) && - NextToken().is(tok::ellipsis)) { - ExprType = FoldExpr; - return ParseFoldExpression(Result, T); - } - ExprType = SimpleExpr; - - // Don't build a paren expression unless we actually match a ')'. - if (!Result.isInvalid() && Tok.is(tok::r_paren)) - Result = - Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.get()); - } - - // Match the ')'. - if (Result.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - - T.consumeClose(); - RParenLoc = T.getCloseLocation(); - return Result; -} - -/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name -/// and we are at the left brace. -/// -/// \verbatim -/// postfix-expression: [C99 6.5.2] -/// '(' type-name ')' '{' initializer-list '}' -/// '(' type-name ')' '{' initializer-list ',' '}' -/// \endverbatim -ExprResult -Parser::ParseCompoundLiteralExpression(ParsedType Ty, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - assert(Tok.is(tok::l_brace) && "Not a compound literal!"); - if (!getLangOpts().C99) // Compound literals don't exist in C90. - Diag(LParenLoc, diag::ext_c99_compound_literal); - ExprResult Result = ParseInitializer(); - if (!Result.isInvalid() && Ty) - return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.get()); - return Result; -} - -/// ParseStringLiteralExpression - This handles the various token types that -/// form string literals, and also handles string concatenation [C99 5.1.1.2, -/// translation phase #6]. -/// -/// \verbatim -/// primary-expression: [C99 6.5.1] -/// string-literal -/// \verbatim -ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { - assert(isTokenStringLiteral() && "Not a string literal!"); - - // String concat. Note that keywords like __func__ and __FUNCTION__ are not - // considered to be strings for concatenation purposes. - SmallVector<Token, 4> StringToks; - - do { - StringToks.push_back(Tok); - ConsumeStringToken(); - } while (isTokenStringLiteral()); - - // Pass the set of string tokens, ready for concatenation, to the actions. - return Actions.ActOnStringLiteral(StringToks, - AllowUserDefinedLiteral ? getCurScope() - : nullptr); -} - -/// ParseGenericSelectionExpression - Parse a C11 generic-selection -/// [C11 6.5.1.1]. -/// -/// \verbatim -/// generic-selection: -/// _Generic ( assignment-expression , generic-assoc-list ) -/// generic-assoc-list: -/// generic-association -/// generic-assoc-list , generic-association -/// generic-association: -/// type-name : assignment-expression -/// default : assignment-expression -/// \endverbatim -ExprResult Parser::ParseGenericSelectionExpression() { - assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); - SourceLocation KeyLoc = ConsumeToken(); - - if (!getLangOpts().C11) - Diag(KeyLoc, diag::ext_c11_generic_selection); - - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume()) - return ExprError(); - - ExprResult ControllingExpr; - { - // C11 6.5.1.1p3 "The controlling expression of a generic selection is - // not evaluated." - EnterExpressionEvaluationContext Unevaluated( - Actions, Sema::ExpressionEvaluationContext::Unevaluated); - ControllingExpr = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (ControllingExpr.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - } - - if (ExpectAndConsume(tok::comma)) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - - SourceLocation DefaultLoc; - TypeVector Types; - ExprVector Exprs; - do { - ParsedType Ty; - if (Tok.is(tok::kw_default)) { - // C11 6.5.1.1p2 "A generic selection shall have no more than one default - // generic association." - if (!DefaultLoc.isInvalid()) { - Diag(Tok, diag::err_duplicate_default_assoc); - Diag(DefaultLoc, diag::note_previous_default_assoc); - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - DefaultLoc = ConsumeToken(); - Ty = nullptr; - } else { - ColonProtectionRAIIObject X(*this); - TypeResult TR = ParseTypeName(); - if (TR.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - Ty = TR.get(); - } - Types.push_back(Ty); - - if (ExpectAndConsume(tok::colon)) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - - // FIXME: These expressions should be parsed in a potentially potentially - // evaluated context. - ExprResult ER( - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); - if (ER.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return ExprError(); - } - Exprs.push_back(ER.get()); - } while (TryConsumeToken(tok::comma)); - - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) - return ExprError(); - - return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, - T.getCloseLocation(), - ControllingExpr.get(), - Types, Exprs); -} - -/// Parse A C++1z fold-expression after the opening paren and optional -/// left-hand-side expression. -/// -/// \verbatim -/// fold-expression: -/// ( cast-expression fold-operator ... ) -/// ( ... fold-operator cast-expression ) -/// ( cast-expression fold-operator ... fold-operator cast-expression ) -ExprResult Parser::ParseFoldExpression(ExprResult LHS, - BalancedDelimiterTracker &T) { - if (LHS.isInvalid()) { - T.skipToEnd(); - return true; - } - - tok::TokenKind Kind = tok::unknown; - SourceLocation FirstOpLoc; - if (LHS.isUsable()) { - Kind = Tok.getKind(); - assert(isFoldOperator(Kind) && "missing fold-operator"); - FirstOpLoc = ConsumeToken(); - } - - assert(Tok.is(tok::ellipsis) && "not a fold-expression"); - SourceLocation EllipsisLoc = ConsumeToken(); - - ExprResult RHS; - if (Tok.isNot(tok::r_paren)) { - if (!isFoldOperator(Tok.getKind())) - return Diag(Tok.getLocation(), diag::err_expected_fold_operator); - - if (Kind != tok::unknown && Tok.getKind() != Kind) - Diag(Tok.getLocation(), diag::err_fold_operator_mismatch) - << SourceRange(FirstOpLoc); - Kind = Tok.getKind(); - ConsumeToken(); - - RHS = ParseExpression(); - if (RHS.isInvalid()) { - T.skipToEnd(); - return true; - } - } - - Diag(EllipsisLoc, getLangOpts().CPlusPlus17 - ? diag::warn_cxx14_compat_fold_expression - : diag::ext_fold_expression); - - T.consumeClose(); - return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind, - EllipsisLoc, RHS.get(), T.getCloseLocation()); -} - -/// ParseExpressionList - Used for C/C++ (argument-)expression-list. -/// -/// \verbatim -/// argument-expression-list: -/// assignment-expression -/// argument-expression-list , assignment-expression -/// -/// [C++] expression-list: -/// [C++] assignment-expression -/// [C++] expression-list , assignment-expression -/// -/// [C++0x] expression-list: -/// [C++0x] initializer-list -/// -/// [C++0x] initializer-list -/// [C++0x] initializer-clause ...[opt] -/// [C++0x] initializer-list , initializer-clause ...[opt] -/// -/// [C++0x] initializer-clause: -/// [C++0x] assignment-expression -/// [C++0x] braced-init-list -/// \endverbatim -bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, - SmallVectorImpl<SourceLocation> &CommaLocs, - llvm::function_ref<void()> Completer) { - bool SawError = false; - while (1) { - if (Tok.is(tok::code_completion)) { - if (Completer) - Completer(); - else - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - cutOffParsing(); - return true; - } - - ExprResult Expr; - if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { - Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); - Expr = ParseBraceInitializer(); - } else - Expr = ParseAssignmentExpression(); - - if (Tok.is(tok::ellipsis)) - Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); - if (Expr.isInvalid()) { - SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch); - SawError = true; - } else { - Exprs.push_back(Expr.get()); - } - - if (Tok.isNot(tok::comma)) - break; - // Move to the next argument, remember where the comma was. - Token Comma = Tok; - CommaLocs.push_back(ConsumeToken()); - - checkPotentialAngleBracketDelimiter(Comma); - } - if (SawError) { - // Ensure typos get diagnosed when errors were encountered while parsing the - // expression list. - for (auto &E : Exprs) { - ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); - if (Expr.isUsable()) E = Expr.get(); - } - } - return SawError; -} - -/// ParseSimpleExpressionList - A simple comma-separated list of expressions, -/// used for misc language extensions. -/// -/// \verbatim -/// simple-expression-list: -/// assignment-expression -/// simple-expression-list , assignment-expression -/// \endverbatim -bool -Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, - SmallVectorImpl<SourceLocation> &CommaLocs) { - while (1) { - ExprResult Expr = ParseAssignmentExpression(); - if (Expr.isInvalid()) - return true; - - Exprs.push_back(Expr.get()); - - if (Tok.isNot(tok::comma)) - return false; - - // Move to the next argument, remember where the comma was. - Token Comma = Tok; - CommaLocs.push_back(ConsumeToken()); - - checkPotentialAngleBracketDelimiter(Comma); - } -} - -/// ParseBlockId - Parse a block-id, which roughly looks like int (int x). -/// -/// \verbatim -/// [clang] block-id: -/// [clang] specifier-qualifier-list block-declarator -/// \endverbatim -void Parser::ParseBlockId(SourceLocation CaretLoc) { - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); - return cutOffParsing(); - } - - // Parse the specifier-qualifier-list piece. - DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS); - - // Parse the block-declarator. - Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteralContext); - DeclaratorInfo.setFunctionDefinitionKind(FDK_Definition); - ParseDeclarator(DeclaratorInfo); - - MaybeParseGNUAttributes(DeclaratorInfo); - - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); -} - -/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks -/// like ^(int x){ return x+1; } -/// -/// \verbatim -/// block-literal: -/// [clang] '^' block-args[opt] compound-statement -/// [clang] '^' block-id compound-statement -/// [clang] block-args: -/// [clang] '(' parameter-list ')' -/// \endverbatim -ExprResult Parser::ParseBlockLiteralExpression() { - assert(Tok.is(tok::caret) && "block literal starts with ^"); - SourceLocation CaretLoc = ConsumeToken(); - - PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, - "block literal parsing"); - - // Enter a scope to hold everything within the block. This includes the - // argument decls, decls within the compound expression, etc. This also - // allows determining whether a variable reference inside the block is - // within or outside of the block. - ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | - Scope::CompoundStmtScope | Scope::DeclScope); - - // Inform sema that we are starting a block. - Actions.ActOnBlockStart(CaretLoc, getCurScope()); - - // Parse the return type if present. - DeclSpec DS(AttrFactory); - Declarator ParamInfo(DS, DeclaratorContext::BlockLiteralContext); - ParamInfo.setFunctionDefinitionKind(FDK_Definition); - // FIXME: Since the return type isn't actually parsed, it can't be used to - // fill ParamInfo with an initial valid range, so do it manually. - ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); - - // If this block has arguments, parse them. There is no ambiguity here with - // the expression case, because the expression case requires a parameter list. - if (Tok.is(tok::l_paren)) { - ParseParenDeclarator(ParamInfo); - // Parse the pieces after the identifier as if we had "int(...)". - // SetIdentifier sets the source range end, but in this case we're past - // that location. - SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); - ParamInfo.SetIdentifier(nullptr, CaretLoc); - ParamInfo.SetRangeEnd(Tmp); - if (ParamInfo.isInvalidType()) { - // If there was an error parsing the arguments, they may have - // tried to use ^(x+y) which requires an argument list. Just - // skip the whole block literal. - Actions.ActOnBlockError(CaretLoc, getCurScope()); - return ExprError(); - } - - MaybeParseGNUAttributes(ParamInfo); - - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); - } else if (!Tok.is(tok::l_brace)) { - ParseBlockId(CaretLoc); - } else { - // Otherwise, pretend we saw (void). - SourceLocation NoLoc; - ParamInfo.AddTypeInfo( - DeclaratorChunk::getFunction(/*HasProto=*/true, - /*IsAmbiguous=*/false, - /*RParenLoc=*/NoLoc, - /*ArgInfo=*/nullptr, - /*NumArgs=*/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()); -} |
