diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-11-08 05:07:16 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-11-08 05:07:16 +0000 |
commit | 0f0af19b058151690ec02d781d0039fb1fc38426 (patch) | |
tree | 628729499c9190870f32a30ddfea3d8c9db273fd /clang/lib/Parse/ParseExpr.cpp | |
parent | 8f6dd44056ceb2821b7692f1a110f91866b1bf2b (diff) | |
download | bcm5719-llvm-0f0af19b058151690ec02d781d0039fb1fc38426.tar.gz bcm5719-llvm-0f0af19b058151690ec02d781d0039fb1fc38426.zip |
[c++1z] N4295: fold-expressions.
This is a new form of expression of the form:
(expr op ... op expr)
where one of the exprs is a parameter pack. It expands into
(expr1 op (expr2onwards op ... op expr))
(and likewise if the pack is on the right). The non-pack operand can be
omitted; in that case, an empty pack gives a fallback value or an error,
depending on the operator.
llvm-svn: 221573
Diffstat (limited to 'clang/lib/Parse/ParseExpr.cpp')
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 60840c6f510..208ead86466 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -216,6 +216,13 @@ bool Parser::isNotExpressionStart() { return isKnownToBeDeclarationSpecifier(); } +static bool isFoldOperator(prec::Level Level) { + return Level > prec::Unknown && Level != prec::Conditional; +} +static bool isFoldOperator(tok::TokenKind Kind) { + return isFoldOperator(getBinOpPrecedence(Kind, false, true)); +} + /// \brief Parse a binary expression that starts with \p LHS and has a /// precedence of at least \p MinPrec. ExprResult @@ -247,6 +254,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { 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; + } + // Special case handling for the ternary operator. ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { @@ -365,7 +382,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus11); } - assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); if (!RHS.isInvalid() && RHSIsInitList) { if (ThisPrec == prec::Assignment) { @@ -1989,11 +2005,15 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { /// 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, @@ -2194,12 +2214,18 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), ArgExprs); } + } else if (Tok.is(tok::ellipsis) && + isFoldOperator(NextToken().getKind())) { + return ParseFoldExpression(ExprResult(), T); } else { InMessageExpressionRAIIObject InMessage(*this, false); Result = ParseExpression(MaybeTypeCast); ExprType = SimpleExpr; + if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) + return ParseFoldExpression(Result, T); + // Don't build a paren expression unless we actually match a ')'. if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = @@ -2357,6 +2383,59 @@ ExprResult Parser::ParseGenericSelectionExpression() { Types, Exprs); } +/// \brief 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().CPlusPlus1z + ? 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 |