From c7214f6510fb612e6731c7e82d0ab4a6678b7de2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 13 May 2019 08:31:14 +0000 Subject: [PATCH] PR41845: Detect and reject mismatched inner/outer pack expansion sizes in fold expressions rather than crashing. llvm-svn: 360563 --- clang/include/clang/AST/ExprCXX.h | 13 +++++++++++-- clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/Sema/SemaTemplateVariadic.cpp | 9 ++++++--- clang/lib/Sema/TreeTransform.h | 17 ++++++++++------- clang/lib/Serialization/ASTReaderStmt.cpp | 1 + clang/lib/Serialization/ASTWriterStmt.cpp | 1 + clang/test/SemaTemplate/cxx1z-fold-expressions.cpp | 10 ++++++++++ 7 files changed, 41 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 05574c2..141fc5d 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -4436,18 +4436,21 @@ class CXXFoldExpr : public Expr { SourceLocation LParenLoc; SourceLocation EllipsisLoc; SourceLocation RParenLoc; + // When 0, the number of expansions is not known. Otherwise, this is one more + // than the number of expansions. + unsigned NumExpansions; Stmt *SubExprs[2]; BinaryOperatorKind Opcode; public: CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS, - SourceLocation RParenLoc) + SourceLocation RParenLoc, Optional NumExpansions) : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary, /*Dependent*/ true, true, true, /*ContainsUnexpandedParameterPack*/ false), LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc), - Opcode(Opcode) { + NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) { SubExprs[0] = LHS; SubExprs[1] = RHS; } @@ -4474,6 +4477,12 @@ public: SourceLocation getEllipsisLoc() const { return EllipsisLoc; } BinaryOperatorKind getOperator() const { return Opcode; } + Optional getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + return None; + } + SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ce3d86a..51302a2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5204,7 +5204,8 @@ public: ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + Optional NumExpansions); ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index d06b7d4..8773f45 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -1176,15 +1176,18 @@ ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, } BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator); - return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc); + return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc, + None); } ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + Optional NumExpansions) { return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS, - Operator, EllipsisLoc, RHS, RParenLoc); + Operator, EllipsisLoc, RHS, RParenLoc, + NumExpansions); } ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ab2ed25..fc8209e 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3254,9 +3254,10 @@ public: ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + Optional NumExpansions) { return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc, - RHS, RParenLoc); + RHS, RParenLoc, NumExpansions); } /// Build an empty C++1z fold-expression with the given operator. @@ -11823,7 +11824,8 @@ TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional NumExpansions; + Optional OrigNumExpansions = E->getNumExpansions(), + NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, @@ -11852,7 +11854,7 @@ TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { return getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), LHS.get(), E->getOperator(), E->getEllipsisLoc(), - RHS.get(), E->getEndLoc()); + RHS.get(), E->getEndLoc(), NumExpansions); } // The transform has determined that we should perform an elementwise @@ -11873,7 +11875,7 @@ TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(), - Result.get(), E->getEndLoc()); + Result.get(), E->getEndLoc(), OrigNumExpansions); if (Result.isInvalid()) return true; } @@ -11890,7 +11892,8 @@ TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), LeftFold ? Result.get() : Out.get(), E->getOperator(), E->getEllipsisLoc(), - LeftFold ? Out.get() : Result.get(), E->getEndLoc()); + LeftFold ? Out.get() : Result.get(), E->getEndLoc(), + OrigNumExpansions); } else if (Result.isUsable()) { // We've got down to a single element; build a binary operator. Result = getDerived().RebuildBinaryOperator( @@ -11915,7 +11918,7 @@ TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(), - Out.get(), E->getEndLoc()); + Out.get(), E->getEndLoc(), OrigNumExpansions); if (Result.isInvalid()) return true; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index ea7c2a4..1470937 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1810,6 +1810,7 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) { E->LParenLoc = ReadSourceLocation(); E->EllipsisLoc = ReadSourceLocation(); E->RParenLoc = ReadSourceLocation(); + E->NumExpansions = Record.readInt(); E->SubExprs[0] = Record.readSubExpr(); E->SubExprs[1] = Record.readSubExpr(); E->Opcode = (BinaryOperatorKind)Record.readInt(); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 2875f25..31fcfa9 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1780,6 +1780,7 @@ void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) { Record.AddSourceLocation(E->LParenLoc); Record.AddSourceLocation(E->EllipsisLoc); Record.AddSourceLocation(E->RParenLoc); + Record.push_back(E->NumExpansions); Record.AddStmt(E->SubExprs[0]); Record.AddStmt(E->SubExprs[1]); Record.push_back(E->Opcode); diff --git a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp index 383f51d..44f3888 100644 --- a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp +++ b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp @@ -92,3 +92,13 @@ template constexpr auto spaceship3(T ...t) { return (t <=> ... <= template constexpr auto binary_conditional1(T ...t) { return (t ?: ...); } // expected-error {{expected expression}} template constexpr auto binary_conditional2(T ...t) { return (... ?: t); } // expected-error {{expected expression}} template constexpr auto binary_conditional3(T ...t) { return (t ?: ... ?: 0); } // expected-error {{expected expression}} + +namespace PR41845 { + template struct Constant {}; + + template struct Sum { + template using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter pack 'Js' that has a different length (1 vs. 2) from outer parameter packs}} + }; + + Sum<1>::type<1, 2> x; // expected-note {{instantiation of}} +} -- 2.7.4