Skip to content

Commit

Permalink
Parse a possible trailing postfix expression suffix after a fold expr…
Browse files Browse the repository at this point in the history
…ession

Summary:
This patch allows the parsing of a postfix expression involving a fold expression, which is legal as a fold-expression is a primary-expression.

See also https://llvm.org/pr38282

Reviewers: rsmith

Reviewed By: rsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D49848

llvm-svn: 338170
  • Loading branch information
Rakete1111 committed Jul 27, 2018
1 parent 69770d3 commit 05141f1
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -1653,6 +1653,7 @@ class Parser : public CodeCompletionHandler {
/// ParenParseOption - Control what ParseParenExpression will parse.
enum ParenParseOption {
SimpleExpr, // Only parse '(' expression ')'
FoldExpr, // Also allow fold-expression <anything>
CompoundStmt, // Also allow '(' compound-statement ')'
CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
CastExpr // Also allow '(' type-name ')' <anything>
Expand Down
20 changes: 15 additions & 5 deletions clang/lib/Parse/ParseExpr.cpp
Expand Up @@ -789,6 +789,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// 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;
Expand Down Expand Up @@ -2523,8 +2527,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
}
} else if (Tok.is(tok::ellipsis) &&
} else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) &&
isFoldOperator(NextToken().getKind())) {
ExprType = FoldExpr;
return ParseFoldExpression(ExprResult(), T);
} else if (isTypeCast) {
// Parse the expression-list.
Expand All @@ -2536,9 +2541,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
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 (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
NextToken().is(tok::ellipsis))
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(),
Expand All @@ -2553,10 +2560,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// expressions are parsed correctly.
Result = Actions.CorrectDelayedTyposInExpr(Result);
}
ExprType = SimpleExpr;

if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
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))
Expand Down
26 changes: 26 additions & 0 deletions clang/test/Parser/cxx1z-fold-expressions.cpp
Expand Up @@ -60,3 +60,29 @@ template <int... N> constexpr int nestedFoldOperator() {
}

static_assert(nestedFoldOperator<3, 1>() == 1);

// A fold-expression is a primary-expression.
template <typename T, typename... Ts>
constexpr auto castSum(Ts... Args) {
return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
}

template <typename... Ts>
constexpr auto simpleSum(Ts... Args) {
return (... + Args).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
}

void prim() {
castSum<int>(1, 2);
// expected-note@-1{{in instantiation of function template specialization}}
simpleSum(1, 2);
// expected-note@-1{{in instantiation of function template specialization}}

struct Number {
int Value;
constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
};

static_assert(castSum<long>(Number{1}, Number{2}) == 3);
static_assert(simpleSum(Number{1}, Number{2}) == 3);
}

0 comments on commit 05141f1

Please sign in to comment.