From: Richard Smith Date: Mon, 13 May 2019 08:31:14 +0000 (+0000) Subject: PR41845: Detect and reject mismatched inner/outer pack expansion sizes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c10f0b96cad0191a4029c4a0cf0f55d30b6ce7dc;p=clang PR41845: Detect and reject mismatched inner/outer pack expansion sizes in fold expressions rather than crashing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360563 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 05574c2312..141fc5d96d 100644 --- a/include/clang/AST/ExprCXX.h +++ b/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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ce3d86aa74..51302a29b4 100644 --- a/include/clang/Sema/Sema.h +++ b/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/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index d06b7d49b4..8773f45c30 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ab2ed258ee..fc8209ef5a 100644 --- a/lib/Sema/TreeTransform.h +++ b/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/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index ea7c2a4595..1470937d51 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/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/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 2875f253d2..31fcfa9919 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/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/test/SemaTemplate/cxx1z-fold-expressions.cpp b/test/SemaTemplate/cxx1z-fold-expressions.cpp index 383f51df21..44f388843b 100644 --- a/test/SemaTemplate/cxx1z-fold-expressions.cpp +++ b/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}} +}