r221573 - [c++1z] N4295: fold-expressions.

Richard Smith richard-llvm at metafoo.co.uk
Fri Nov 7 21:07:16 PST 2014


Author: rsmith
Date: Fri Nov  7 23:07:16 2014
New Revision: 221573

URL: http://llvm.org/viewvc/llvm-project?rev=221573&view=rev
Log:
[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.

Added:
    cfe/trunk/test/CodeGenCXX/cxx1z-fold-expression.cpp
    cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp
    cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp
Modified:
    cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/StmtNodes.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/SemaCXX/cxx0x-compat.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Fri Nov  7 23:07:16 2014
@@ -2257,6 +2257,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplatePa
 DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
 DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
 DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
+DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
 
 // These literals (all of them) do not need any action.

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Nov  7 23:07:16 2014
@@ -3818,6 +3818,69 @@ public:
   }
 };
 
+/// \brief Represents a folding of a pack over an operator.
+///
+/// This expression is always dependent and represents a pack expansion of the
+/// forms:
+///
+///    ( expr op ... )
+///    ( ... op expr )
+///    ( expr op ... op expr )
+class CXXFoldExpr : public Expr {
+  SourceLocation LParenLoc;
+  SourceLocation EllipsisLoc;
+  SourceLocation RParenLoc;
+  Stmt *SubExprs[2];
+  BinaryOperatorKind Opcode;
+
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+public:
+  CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS,
+              BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS,
+              SourceLocation RParenLoc)
+      : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary,
+             /*Dependent*/ true, true, true,
+             /*ContainsUnexpandedParameterPack*/ false),
+        LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
+        Opcode(Opcode) {
+    SubExprs[0] = LHS;
+    SubExprs[1] = RHS;
+  }
+  CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {}
+
+  Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); }
+  Expr *getRHS() const { return static_cast<Expr*>(SubExprs[1]); }
+
+  /// Does this produce a right-associated sequence of operators?
+  bool isRightFold() const {
+    return getLHS() && getLHS()->containsUnexpandedParameterPack();
+  }
+  /// Does this produce a left-associated sequence of operators?
+  bool isLeftFold() const { return !isRightFold(); }
+  /// Get the pattern, that is, the operand that contains an unexpanded pack.
+  Expr *getPattern() const { return isLeftFold() ? getRHS() : getLHS(); }
+  /// Get the operand that doesn't contain a pack, for a binary fold.
+  Expr *getInit() const { return isLeftFold() ? getLHS() : getRHS(); }
+
+  SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+  BinaryOperatorKind getOperator() const { return Opcode; }
+
+  SourceLocation getLocStart() const LLVM_READONLY {
+    return LParenLoc;
+  }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return RParenLoc;
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXFoldExprClass;
+  }
+
+  // Iterators
+  child_range children() { return child_range(SubExprs, SubExprs + 2); }
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Fri Nov  7 23:07:16 2014
@@ -2279,6 +2279,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplatePa
 DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
 DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
 DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
+DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
 
 // These literals (all of them) do not need any action.

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Fri Nov  7 23:07:16 2014
@@ -682,7 +682,18 @@ def err_explicit_spec_non_template : Err
 def err_default_template_template_parameter_not_template : Error<
   "default template argument for a template template parameter must be a class "
   "template">;
-  
+
+def ext_fold_expression : ExtWarn<
+  "pack fold expression is a C++1z extension">,
+  InGroup<CXX1z>;
+def warn_cxx14_compat_fold_expression : Warning<
+  "pack fold expression is incompatible with C++ standards before C++1z">,
+  InGroup<CXXPre1zCompat>, DefaultIgnore;
+def err_expected_fold_operator : Error<
+  "expected a foldable binary operator in fold expression">;
+def err_fold_operator_mismatch : Error<
+  "operators in fold expression must be the same">;
+
 def err_ctor_init_missing_comma : Error<
   "missing ',' between base or member initializers">;
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Nov  7 23:07:16 2014
@@ -3784,6 +3784,14 @@ def err_ellipsis_in_declarator_not_param
 def err_sizeof_pack_no_pack_name : Error<
   "%0 does not refer to the name of a parameter pack">;
 
+def err_fold_expression_packs_both_sides : Error<
+  "binary fold expression has unexpanded parameter packs in both operands">;
+def err_fold_expression_empty : Error<
+  "unary fold expression has empty expansion for operator '%0' "
+  "with no fallback value">;
+def err_fold_expression_bad_operand : Error<
+  "expression not permitted as operand of fold expression">;
+
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
 def err_unexpected_namespace : Error<

Modified: cfe/trunk/include/clang/Basic/StmtNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
+++ cfe/trunk/include/clang/Basic/StmtNodes.td Fri Nov  7 23:07:16 2014
@@ -135,6 +135,7 @@ def SubstNonTypeTemplateParmPackExpr : D
 def FunctionParmPackExpr : DStmt<Expr>;
 def MaterializeTemporaryExpr : DStmt<Expr>;
 def LambdaExpr : DStmt<Expr>;
+def CXXFoldExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Nov  7 23:07:16 2014
@@ -1392,6 +1392,8 @@ private:
   
   ExprResult ParseObjCBoolLiteral();
 
+  ExprResult ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T);
+
   //===--------------------------------------------------------------------===//
   // C++ Expressions
   ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Nov  7 23:07:16 2014
@@ -3714,6 +3714,10 @@ public:
                                         bool GNUSyntax,
                                         ExprResult Init);
 
+private:
+  static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind);
+
+public:
   ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
                         tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr);
   ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc,
@@ -4287,6 +4291,17 @@ public:
                             void *TyOrExpr,
                             SourceLocation RParenLoc);
 
+  /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ).
+  ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+                              tok::TokenKind Operator,
+                              SourceLocation EllipsisLoc, Expr *RHS,
+                              SourceLocation RParenLoc);
+  ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+                              BinaryOperatorKind Operator,
+                              SourceLocation EllipsisLoc, Expr *RHS,
+                              SourceLocation RParenLoc);
+  ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+                                   BinaryOperatorKind Operator);
 
   //// ActOnCXXThis -  Parse 'this' pointer.
   ExprResult ActOnCXXThis(SourceLocation loc);

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Fri Nov  7 23:07:16 2014
@@ -1332,7 +1332,8 @@ namespace clang {
       EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
       EXPR_FUNCTION_PARM_PACK,    // FunctionParmPackExpr
       EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
-      
+      EXPR_CXX_FOLD,              // CXXFoldExpr
+
       // CUDA
       EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
 

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Nov  7 23:07:16 2014
@@ -2887,6 +2887,7 @@ bool Expr::HasSideEffects(const ASTConte
   case SubstNonTypeTemplateParmPackExprClass:
   case FunctionParmPackExprClass:
   case TypoExprClass:
+  case CXXFoldExprClass:
     llvm_unreachable("shouldn't see dependent / unresolved nodes here");
 
   case DeclRefExprClass:

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Fri Nov  7 23:07:16 2014
@@ -182,6 +182,7 @@ static Cl::Kinds ClassifyInternal(ASTCon
   case Expr::AsTypeExprClass:
   case Expr::ObjCIndirectCopyRestoreExprClass:
   case Expr::AtomicExprClass:
+  case Expr::CXXFoldExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov  7 23:07:16 2014
@@ -8661,6 +8661,7 @@ static ICEDiag CheckICE(const Expr* E, c
   case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
   case Expr::LambdaExprClass:
+  case Expr::CXXFoldExprClass:
     return ICEDiag(IK_NotICE, E->getLocStart());
 
   case Expr::InitListExprClass: {

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Fri Nov  7 23:07:16 2014
@@ -3209,12 +3209,35 @@ recurse:
       mangleFunctionParam(cast<ParmVarDecl>(Pack));
     break;
   }
-      
+
   case Expr::MaterializeTemporaryExprClass: {
     mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
     break;
   }
-      
+
+  case Expr::CXXFoldExprClass: {
+    auto *FE = cast<CXXFoldExpr>(E);
+    if (!FE->getLHS())
+      Out << "fl";
+    else if (!FE->getRHS())
+      Out << "fr";
+    else
+      Out << "fx";
+
+    if (FE->getOperator() == BO_PtrMemD)
+      Out << "ds";
+    else
+      mangleOperatorName(
+          BinaryOperator::getOverloadedOperator(FE->getOperator()),
+          /*Arity=*/2);
+
+    if (FE->getLHS())
+      mangleExpression(FE->getLHS());
+    if (FE->getRHS())
+      mangleExpression(FE->getRHS());
+    break;
+  }
+
   case Expr::CXXThisExprClass:
     Out << "fpT";
     break;

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Nov  7 23:07:16 2014
@@ -2022,6 +2022,20 @@ void StmtPrinter::VisitMaterializeTempor
   PrintExpr(Node->GetTemporaryExpr());
 }
 
+void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
+  OS << "(";
+  if (E->getLHS()) {
+    PrintExpr(E->getLHS());
+    OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
+  }
+  OS << "...";
+  if (E->getRHS()) {
+    OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
+    PrintExpr(E->getRHS());
+  }
+  OS << ")";
+}
+
 // Obj-C
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Fri Nov  7 23:07:16 2014
@@ -1238,6 +1238,11 @@ void StmtProfiler::VisitMaterializeTempo
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
+  VisitExpr(S);
+  ID.AddInteger(S->getOperator());
+}
+
 void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
   VisitExpr(E);  
 }

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Nov  7 23:07:16 2014
@@ -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(ExprR
       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(ExprR
       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::ParseBuiltinPrimaryEx
 ///       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(ParenParseO
       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::ParseGenericSelection
                                            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

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Fri Nov  7 23:07:16 2014
@@ -1048,6 +1048,7 @@ CanThrowResult Sema::canThrow(const Expr
   case Expr::CXXDependentScopeMemberExprClass:
   case Expr::CXXUnresolvedConstructExprClass:
   case Expr::DependentScopeDeclRefExprClass:
+  case Expr::CXXFoldExprClass:
     return CT_Dependent;
 
   case Expr::AsTypeExprClass:

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Nov  7 23:07:16 2014
@@ -9164,8 +9164,7 @@ static QualType CheckIndirectionOperand(
   return Result;
 }
 
-static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode(
-  tok::TokenKind Kind) {
+BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) {
   BinaryOperatorKind Opc;
   switch (Kind) {
   default: llvm_unreachable("Unknown binop!");

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Fri Nov  7 23:07:16 2014
@@ -935,3 +935,108 @@ Sema::getTemplateArgumentPackExpansionPa
 
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
+
+static void CheckFoldOperand(Sema &S, Expr *E) {
+  if (!E)
+    return;
+
+  E = E->IgnoreImpCasts();
+  if (isa<BinaryOperator>(E) || isa<AbstractConditionalOperator>(E)) {
+    S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand)
+        << E->getSourceRange()
+        << FixItHint::CreateInsertion(E->getLocStart(), "(")
+        << FixItHint::CreateInsertion(E->getLocEnd(), ")");
+  }
+}
+
+ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+                                  tok::TokenKind Operator,
+                                  SourceLocation EllipsisLoc, Expr *RHS,
+                                  SourceLocation RParenLoc) {
+  // LHS and RHS must be cast-expressions. We allow an arbitrary expression
+  // in the parser and reduce down to just cast-expressions here.
+  CheckFoldOperand(*this, LHS);
+  CheckFoldOperand(*this, RHS);
+
+  // [expr.prim.fold]p3:
+  //   In a binary fold, op1 and op2 shall be the same fold-operator, and
+  //   either e1 shall contain an unexpanded parameter pack or e2 shall contain
+  //   an unexpanded parameter pack, but not both.
+  if (LHS && RHS &&
+      LHS->containsUnexpandedParameterPack() ==
+          RHS->containsUnexpandedParameterPack()) {
+    return Diag(EllipsisLoc,
+                LHS->containsUnexpandedParameterPack()
+                    ? diag::err_fold_expression_packs_both_sides
+                    : diag::err_pack_expansion_without_parameter_packs)
+        << LHS->getSourceRange() << RHS->getSourceRange();
+  }
+
+  // [expr.prim.fold]p2:
+  //   In a unary fold, the cast-expression shall contain an unexpanded
+  //   parameter pack.
+  if (!LHS || !RHS) {
+    Expr *Pack = LHS ? LHS : RHS;
+    assert(Pack && "fold expression with neither LHS nor RHS");
+    if (!Pack->containsUnexpandedParameterPack())
+      return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+             << Pack->getSourceRange();
+  }
+
+  BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);
+  return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc);
+}
+
+ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+                                  BinaryOperatorKind Operator,
+                                  SourceLocation EllipsisLoc, Expr *RHS,
+                                  SourceLocation RParenLoc) {
+  return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
+                                   Operator, EllipsisLoc, RHS, RParenLoc);
+}
+
+ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+                                       BinaryOperatorKind Operator) {
+  // [temp.variadic]p9:
+  //   If N is zero for a unary fold-expression, the value of the expression is
+  //       *   ->  1
+  //       +   ->  int()
+  //       &   ->  -1
+  //       |   ->  int()
+  //       &&  ->  true
+  //       ||  ->  false
+  //       ,   ->  void()
+  //   if the operator is not listed [above], the instantiation is ill-formed.
+  //
+  // Note that we need to use something like int() here, not merely 0, to
+  // prevent the result from being a null pointer constant.
+  QualType ScalarType;
+  switch (Operator) {
+  case BO_Add:
+    ScalarType = Context.IntTy;
+    break;
+  case BO_Mul:
+    return ActOnIntegerConstant(EllipsisLoc, 1);
+  case BO_Or:
+    ScalarType = Context.IntTy;
+    break;
+  case BO_And:
+    return CreateBuiltinUnaryOp(EllipsisLoc, UO_Minus,
+                                ActOnIntegerConstant(EllipsisLoc, 1).get());
+  case BO_LOr:
+    return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false);
+  case BO_LAnd:
+    return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_true);
+  case BO_Comma:
+    ScalarType = Context.VoidTy;
+    break;
+
+  default:
+    return Diag(EllipsisLoc, diag::err_fold_expression_empty)
+        << BinaryOperator::getOpcodeStr(Operator);
+  }
+
+  return new (Context) CXXScalarValueInitExpr(
+      ScalarType, Context.getTrivialTypeSourceInfo(ScalarType, EllipsisLoc),
+      EllipsisLoc);
+}

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Nov  7 23:07:16 2014
@@ -2784,6 +2784,27 @@ public:
     return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
   }
 
+  /// \brief Build a new C++1z fold-expression.
+  ///
+  /// By default, performs semantic analysis in order to build a new fold
+  /// expression.
+  ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+                                BinaryOperatorKind Operator,
+                                SourceLocation EllipsisLoc, Expr *RHS,
+                                SourceLocation RParenLoc) {
+    return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,
+                                      RHS, RParenLoc);
+  }
+
+  /// \brief Build an empty C++1z fold-expression with the given operator.
+  ///
+  /// By default, produces the fallback value for the fold-expression, or
+  /// produce an error if there is no fallback value.
+  ExprResult RebuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+                                     BinaryOperatorKind Operator) {
+    return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
+  }
+
   /// \brief Build a new atomic operation expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -9565,6 +9586,128 @@ TreeTransform<Derived>::TransformMateria
 }
 
 template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
+  Expr *Pattern = E->getPattern();
+
+  SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+  getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
+  assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+  // Determine whether the set of unexpanded parameter packs can and should
+  // be expanded.
+  bool Expand = true;
+  bool RetainExpansion = false;
+  Optional<unsigned> NumExpansions;
+  if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
+                                           Pattern->getSourceRange(),
+                                           Unexpanded,
+                                           Expand, RetainExpansion,
+                                           NumExpansions))
+    return true;
+
+  if (!Expand) {
+    // Do not expand any packs here, just transform and rebuild a fold
+    // expression.
+    Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+
+    ExprResult LHS =
+        E->getLHS() ? getDerived().TransformExpr(E->getLHS()) : ExprResult();
+    if (LHS.isInvalid())
+      return true;
+
+    ExprResult RHS =
+        E->getRHS() ? getDerived().TransformExpr(E->getRHS()) : ExprResult();
+    if (RHS.isInvalid())
+      return true;
+
+    if (!getDerived().AlwaysRebuild() &&
+        LHS.get() == E->getLHS() && RHS.get() == E->getRHS())
+      return E;
+
+    return getDerived().RebuildCXXFoldExpr(
+        E->getLocStart(), LHS.get(), E->getOperator(), E->getEllipsisLoc(),
+        RHS.get(), E->getLocEnd());
+  }
+
+  // The transform has determined that we should perform an elementwise
+  // expansion of the pattern. Do so.
+  ExprResult Result = getDerived().TransformExpr(E->getInit());
+  if (Result.isInvalid())
+    return true;
+  bool LeftFold = E->isLeftFold();
+
+  // If we're retaining an expansion for a right fold, it is the innermost
+  // component and takes the init (if any).
+  if (!LeftFold && RetainExpansion) {
+    ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+    ExprResult Out = getDerived().TransformExpr(Pattern);
+    if (Out.isInvalid())
+      return true;
+
+    Result = getDerived().RebuildCXXFoldExpr(
+        E->getLocStart(), Out.get(), E->getOperator(), E->getEllipsisLoc(),
+        Result.get(), E->getLocEnd());
+    if (Result.isInvalid())
+      return true;
+  }
+
+  for (unsigned I = 0; I != *NumExpansions; ++I) {
+    Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
+        getSema(), LeftFold ? I : *NumExpansions - I - 1);
+    ExprResult Out = getDerived().TransformExpr(Pattern);
+    if (Out.isInvalid())
+      return true;
+
+    if (Out.get()->containsUnexpandedParameterPack()) {
+      // We still have a pack; retain a pack expansion for this slice.
+      Result = getDerived().RebuildCXXFoldExpr(
+          E->getLocStart(),
+          LeftFold ? Result.get() : Out.get(),
+          E->getOperator(), E->getEllipsisLoc(),
+          LeftFold ? Out.get() : Result.get(),
+          E->getLocEnd());
+    } else if (Result.isUsable()) {
+      // We've got down to a single element; build a binary operator.
+      Result = getDerived().RebuildBinaryOperator(
+          E->getEllipsisLoc(), E->getOperator(),
+          LeftFold ? Result.get() : Out.get(),
+          LeftFold ? Out.get() : Result.get());
+    } else
+      Result = Out;
+
+    if (Result.isInvalid())
+      return true;
+  }
+
+  // If we're retaining an expansion for a left fold, it is the outermost
+  // component and takes the complete expansion so far as its init (if any).
+  if (LeftFold && RetainExpansion) {
+    ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+    ExprResult Out = getDerived().TransformExpr(Pattern);
+    if (Out.isInvalid())
+      return true;
+
+    Result = getDerived().RebuildCXXFoldExpr(
+        E->getLocStart(), Result.get(),
+        E->getOperator(), E->getEllipsisLoc(),
+        Out.get(), E->getLocEnd());
+    if (Result.isInvalid())
+      return true;
+  }
+
+  // If we had no init and an empty pack, and we're not retaining an expansion,
+  // then produce a fallback value or error.
+  if (Result.isUnset())
+    return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(),
+                                                E->getOperator());
+
+  return Result;
+}
+
+template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
     CXXStdInitializerListExpr *E) {

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Fri Nov  7 23:07:16 2014
@@ -1580,6 +1580,16 @@ void ASTStmtReader::VisitMaterializeTemp
   E->setExtendingDecl(VD, ManglingNumber);
 }
 
+void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
+  VisitExpr(E);
+  E->LParenLoc = ReadSourceLocation(Record, Idx);
+  E->EllipsisLoc = ReadSourceLocation(Record, Idx);
+  E->RParenLoc = ReadSourceLocation(Record, Idx);
+  E->SubExprs[0] = Reader.ReadSubExpr();
+  E->SubExprs[1] = Reader.ReadSubExpr();
+  E->Opcode = (BinaryOperatorKind)Record[Idx++];
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   E->SourceExpr = Reader.ReadSubExpr();
@@ -2908,7 +2918,11 @@ Stmt *ASTReader::ReadStmtFromStream(Modu
     case EXPR_MATERIALIZE_TEMPORARY:
       S = new (Context) MaterializeTemporaryExpr(Empty);
       break;
-        
+
+    case EXPR_CXX_FOLD:
+      S = new (Context) CXXFoldExpr(Empty);
+      break;
+
     case EXPR_OPAQUE_VALUE:
       S = new (Context) OpaqueValueExpr(Empty);
       break;

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Fri Nov  7 23:07:16 2014
@@ -1579,6 +1579,17 @@ void ASTStmtWriter::VisitMaterializeTemp
   Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
 }
 
+void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
+  VisitExpr(E);
+  Writer.AddSourceLocation(E->LParenLoc, Record);
+  Writer.AddSourceLocation(E->EllipsisLoc, Record);
+  Writer.AddSourceLocation(E->RParenLoc, Record);
+  Writer.AddStmt(E->SubExprs[0]);
+  Writer.AddStmt(E->SubExprs[1]);
+  Record.push_back(E->Opcode);
+  Code = serialization::EXPR_CXX_FOLD;
+}
+
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   Writer.AddStmt(E->getSourceExpr());

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Nov  7 23:07:16 2014
@@ -752,6 +752,7 @@ void ExprEngine::Visit(const Stmt *S, Ex
     case Stmt::CXXTryStmtClass:
     case Stmt::CXXTypeidExprClass:
     case Stmt::CXXUuidofExprClass:
+    case Stmt::CXXFoldExprClass:
     case Stmt::MSPropertyRefExprClass:
     case Stmt::CXXUnresolvedConstructExprClass:
     case Stmt::DependentScopeDeclRefExprClass:

Added: cfe/trunk/test/CodeGenCXX/cxx1z-fold-expression.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-fold-expression.cpp?rev=221573&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-fold-expression.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-fold-expression.cpp Fri Nov  7 23:07:16 2014
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++1z -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+template<int> struct A {};
+template<int ...N> void foldr(A<(N + ...)>);
+template<int ...N> void foldl(A<(... + N)>);
+template<int ...N> void foldr1(A<(N + ... + 1)>);
+template<int ...N> void foldl1(A<(1 + ... + N)>);
+void use() {
+  foldr<1, 2, 3>({});
+  foldl<1, 2, 3>({});
+  foldr1<1, 2, 3>({});
+  foldl1<1, 2, 3>({});
+  // CHECK-DAG: @_Z5foldrIJLi1ELi2ELi3EEEv1AIXfrplT_EE(
+  // CHECK-DAG: @_Z5foldlIJLi1ELi2ELi3EEEv1AIXflplT_EE(
+  // CHECK-DAG: @_Z6foldr1IJLi1ELi2ELi3EEEv1AIXfxplT_Li1EEE(
+  // CHECK-DAG: @_Z6foldl1IJLi1ELi2ELi3EEEv1AIXfxplLi1ET_EE(
+}
+
+template<int ...N> using Foldr = A<(N + ...)>;
+template<int ...N> using Foldl = A<(... + N)>;
+template<int ...N> using Foldr1 = A<(N + ... + 1)>;
+template<int ...N> using Foldl1 = A<(1 + ... + N)>;
+
+template<int ...A> struct Partial {
+  template<int ...B> void foldr(Foldr<A..., B..., A..., B...>);
+  template<int ...B> void foldl(Foldr<A..., B..., A..., B...>);
+  template<int ...B> void foldr1(Foldr1<A..., B..., A..., B...>);
+  template<int ...B> void foldl1(Foldl1<A..., B..., A..., B...>);
+};
+void use(Partial<1, 2> p) {
+  p.foldr<3, 4>({});
+  p.foldl<3, 4>({});
+  p.foldr1<3, 4>({});
+  p.foldl1<3, 4>({});
+  // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE5foldrIJLi3ELi4EEEEv1AIXplLi1EplLi2EfxplT_plLi1EplLi2EfrplT_EE(
+  // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE5foldlIJLi3ELi4EEEEv1AIXplLi1EplLi2EfxplT_plLi1EplLi2EfrplT_EE(
+  // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE6foldr1IJLi3ELi4EEEEv1AIXplLi1EplLi2EfxplT_plLi1EplLi2EfxplT_Li1EEE(
+  // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE6foldl1IJLi3ELi4EEEEv1AIXfxplplplfxplplplLi1ELi1ELi2ET_Li1ELi2ET_EE(
+}
+
+extern int n;
+template<int ...N> void f() {
+  (n = ... = N);
+}
+template void f<>();

Added: cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp?rev=221573&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp (added)
+++ cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp Fri Nov  7 23:07:16 2014
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename ...T> constexpr auto sum(T ...t) { return (... + t); }
+template<typename ...T> constexpr auto product(T ...t) { return (t * ...); }
+template<typename ...T> constexpr auto all(T ...t) { return (true && ... && t); }
+template<typename ...T> constexpr auto all2(T ...t) { return (t && ... && true); }
+
+int k1 = (1 + ... + 2); // expected-error {{does not contain any unexpanded parameter packs}}
+int k2 = (1 + ...); // expected-error {{does not contain any unexpanded parameter packs}}
+int k3 = (... + 2); // expected-error {{does not contain any unexpanded parameter packs}}
+
+template<int ...N> void bad1() { (N + ... + N); } // expected-error {{unexpanded parameter packs in both operands}}
+// FIXME: it would be reasonable to support this as an extension.
+template<int ...N> void bad2() { (2 * N + ... + 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N> void bad3() { (2 + N * ... * 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N, int ...M> void bad4(int (&...x)[N]) { (N + M * ... * 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N, int ...M> void fixed4(int (&...x)[N]) { ((N + M) * ... * 1); }
+
+// Parens are mandatory.
+template<int ...N> void bad5() { N + ...; } // expected-error {{expected expression}} expected-error +{{}}
+template<int ...N> void bad6() { ... + N; } // expected-error {{expected expression}}
+template<int ...N> void bad7() { N + ... + N; } // expected-error {{expected expression}} expected-error +{{}}
+
+// Must have a fold-operator in the relevant places.
+template<int ...N> int bad8() { return (N + ... * 3); } // expected-error {{operators in fold expression must be the same}}
+template<int ...N> int bad9() { return (3 + ... * N); } // expected-error {{operators in fold expression must be the same}}
+template<int ...N> int bad10() { return (3 ? ... : N); } // expected-error +{{}} expected-note {{to match}}
+template<int ...N> int bad11() { return (N + ... 0); } // expected-error {{expected a foldable binary operator}} expected-error {{expected expression}}
+template<int ...N> int bad12() { return (... N); } // expected-error {{expected expression}}

Modified: cfe/trunk/test/SemaCXX/cxx0x-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-compat.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-compat.cpp Fri Nov  7 23:07:16 2014
@@ -41,9 +41,15 @@ void h(size_t foo, size_t bar) {
 #define _x + 1
 char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal suffix}}
 
+template<int ...N> int f() { // expected-warning {{C++11 extension}}
+  return (N + ...); // expected-warning {{C++1z extension}}
+}
+
 #else
 
 auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++14}}
 static_assert(true); // expected-warning {{incompatible with C++ standards before C++1z}}
 
+template<int ...N> int f() { return (N + ...); } // expected-warning {{incompatible with C++ standards before C++1z}}
+
 #endif

Added: cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp?rev=221573&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp (added)
+++ cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp Fri Nov  7 23:07:16 2014
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename ...T> constexpr auto sum(T ...t) { return (... + t); }
+template<typename ...T> constexpr auto product(T ...t) { return (t * ...); }
+template<typename ...T> constexpr auto all(T ...t) { return (true && ... && t); }
+template<typename ...T> constexpr auto dumb(T ...t) { return (false && ... && t); }
+
+static_assert(sum(1, 2, 3, 4, 5) == 15);
+static_assert(product(1, 2, 3, 4, 5) == 120);
+static_assert(!all(true, true, false, true, false));
+static_assert(all(true, true, true, true, true));
+static_assert(!dumb(true, true, true, true, true));
+
+struct S {
+  int a, b, c, d, e;
+};
+template<typename ...T> constexpr auto increment_all(T &...t) {
+  (++t, ...);
+}
+constexpr bool check() {
+  S s = { 1, 2, 3, 4, 5 };
+  increment_all(s.a, s.b, s.c, s.d, s.e);
+  return s.a == 2 && s.b == 3 && s.c == 4 && s.d == 5 && s.e == 6;
+}
+static_assert(check());
+
+template<int ...N> void empty() {
+  static_assert((N + ...) == 0);
+  static_assert((N * ...) == 1);
+  static_assert((N | ...) == 0);
+  static_assert((N & ...) == -1);
+  static_assert((N || ...) == false);
+  static_assert((N && ...) == true);
+  (N, ...);
+}
+template void empty<>();
+
+// An empty fold-expression isn't a null pointer just because it's an integer
+// with value 0.
+template<int ...N> void null_ptr() {
+  void *p = (N + ...); // expected-error {{rvalue of type 'int'}}
+  void *q = (N | ...); // expected-error {{rvalue of type 'int'}}
+}
+template void null_ptr<>(); // expected-note {{in instantiation of}}
+
+template<int ...N> void bad_empty() {
+  (N - ...); // expected-error {{empty expansion for operator '-' with no fallback}}
+  (N / ...); // expected-error {{empty expansion for operator '/' with no fallback}}
+  (N % ...); // expected-error {{empty expansion for operator '%' with no fallback}}
+  (N = ...); // expected-error {{empty expansion for operator '=' with no fallback}}
+}
+template void bad_empty<>(); // expected-note {{in instantiation of}}
+
+template<int ...N> void empty_with_base() {
+  extern int k;
+  (k = ... = N); // expected-warning{{unused}}
+
+  // FIXME: We misparse these. The first one looks a lot loke a declaration;
+  // it's not clear what's happening in the second one.
+  void (k = ... = N); // expected-error {{expected ')'}} expected-note {{to match}}
+  (void) (k = ... = N); // expected-error {{expected ')'}} expected-note {{to match}}
+}
+template void empty_with_base<>(); // expected-note {{in instantiation of}}
+template void empty_with_base<1>();
+
+struct A {
+  struct B {
+    struct C {
+      struct D {
+        int e;
+      } d;
+    } c;
+  } b;
+} a;
+template<typename T, typename ...Ts> constexpr decltype(auto) apply(T &t, Ts ...ts) {
+  return (t.*....*ts);
+}
+static_assert(&apply(a, &A::b, &A::B::c, &A::B::C::d, &A::B::C::D::e) == &a.b.c.d.e);

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Fri Nov  7 23:07:16 2014
@@ -229,6 +229,7 @@ CXCursor cxcursor::MakeCXCursor(const St
   case Stmt::CXXBindTemporaryExprClass:
   case Stmt::CXXDefaultArgExprClass:
   case Stmt::CXXDefaultInitExprClass:
+  case Stmt::CXXFoldExprClass:
   case Stmt::CXXStdInitializerListExprClass:
   case Stmt::CXXScalarValueInitExprClass:
   case Stmt::CXXUuidofExprClass:

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=221573&r1=221572&r2=221573&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri Nov  7 23:07:16 2014
@@ -524,11 +524,13 @@ as the draft C++1z standard evolves.</p>
     <th>C++1z Proposal</th>
     <th>Available in Clang?</th>
  </tr>
+    <!-- Issaquah papers -->
     <tr>
       <td><tt>static_assert</tt> with no message</td>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3928.pdf">N3928</a></td>
       <td class="full" align="center">Clang 3.5</td>
     </tr>
+    <!-- Rapperswil papers -->
     <tr>
       <td>Disabling trigraph expansion by default</td>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3981.html">N3981</a></td>
@@ -544,6 +546,12 @@ as the draft C++1z standard evolves.</p>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">N4051</a></td>
       <td class="full" align="center">Clang 3.5</td>
     </tr>
+    <!-- Urbana papers -->
+    <tr>
+      <td>Fold expressions</td>
+      <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">-->N4295<!--</a>--></td>
+      <td class="svn" align="center">SVN</td>
+    </tr>
 </table>
 
 <h2 id="ts">Technical specifications and standing documents</h2>





More information about the cfe-commits mailing list