]> granicus.if.org Git - clang/commitdiff
Parse a possible trailing postfix expression suffix after a fold expression
authorNicolas Lesser <blitzrakete@gmail.com>
Fri, 27 Jul 2018 21:55:12 +0000 (21:55 +0000)
committerNicolas Lesser <blitzrakete@gmail.com>
Fri, 27 Jul 2018 21:55:12 +0000 (21:55 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338170 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Parser.h
lib/Parse/ParseExpr.cpp
test/Parser/cxx1z-fold-expressions.cpp

index d7b83803af202e2ed2c1691480e996469073fd60..41ccabf3808941e36db3de5d97061aca282ddd34 100644 (file)
@@ -1653,6 +1653,7 @@ private:
   /// 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>
index 4a0e1c5e34130daa6b6045830e7ff0cb94e299d5..5a70c9e2953184a1f9a232a4198d542de71b0443 100644 (file)
@@ -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;
@@ -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.
@@ -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(),
@@ -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))
index 342f11555fa7863a22170dee19a92eec05a03ab0..93ee6f20ffc6d044fb5f9f683a18db27153949b5 100644 (file)
@@ -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);
+}