Selaa lähdekoodia

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

Richard Smith 6 vuotta sitten
vanhempi
commit
c10f0b96ca

+ 11 - 2
include/clang/AST/ExprCXX.h

@@ -4436,18 +4436,21 @@ class CXXFoldExpr : public Expr {
   SourceLocation LParenLoc;
   SourceLocation LParenLoc;
   SourceLocation EllipsisLoc;
   SourceLocation EllipsisLoc;
   SourceLocation RParenLoc;
   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];
   Stmt *SubExprs[2];
   BinaryOperatorKind Opcode;
   BinaryOperatorKind Opcode;
 
 
 public:
 public:
   CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS,
   CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS,
               BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS,
               BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS,
-              SourceLocation RParenLoc)
+              SourceLocation RParenLoc, Optional<unsigned> NumExpansions)
       : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary,
       : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary,
              /*Dependent*/ true, true, true,
              /*Dependent*/ true, true, true,
              /*ContainsUnexpandedParameterPack*/ false),
              /*ContainsUnexpandedParameterPack*/ false),
         LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
         LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
-        Opcode(Opcode) {
+        NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) {
     SubExprs[0] = LHS;
     SubExprs[0] = LHS;
     SubExprs[1] = RHS;
     SubExprs[1] = RHS;
   }
   }
@@ -4474,6 +4477,12 @@ public:
   SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
   SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
   BinaryOperatorKind getOperator() const { return Opcode; }
   BinaryOperatorKind getOperator() const { return Opcode; }
 
 
+  Optional<unsigned> getNumExpansions() const {
+    if (NumExpansions)
+      return NumExpansions - 1;
+    return None;
+  }
+
   SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; }
   SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; }
 
 
   SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
   SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }

+ 2 - 1
include/clang/Sema/Sema.h

@@ -5204,7 +5204,8 @@ public:
   ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
   ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
                               BinaryOperatorKind Operator,
                               BinaryOperatorKind Operator,
                               SourceLocation EllipsisLoc, Expr *RHS,
                               SourceLocation EllipsisLoc, Expr *RHS,
-                              SourceLocation RParenLoc);
+                              SourceLocation RParenLoc,
+                              Optional<unsigned> NumExpansions);
   ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
   ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
                                    BinaryOperatorKind Operator);
                                    BinaryOperatorKind Operator);
 
 

+ 6 - 3
lib/Sema/SemaTemplateVariadic.cpp

@@ -1176,15 +1176,18 @@ ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
   }
   }
 
 
   BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);
   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,
 ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
                                   BinaryOperatorKind Operator,
                                   BinaryOperatorKind Operator,
                                   SourceLocation EllipsisLoc, Expr *RHS,
                                   SourceLocation EllipsisLoc, Expr *RHS,
-                                  SourceLocation RParenLoc) {
+                                  SourceLocation RParenLoc,
+                                  Optional<unsigned> NumExpansions) {
   return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
   return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
-                                   Operator, EllipsisLoc, RHS, RParenLoc);
+                                   Operator, EllipsisLoc, RHS, RParenLoc,
+                                   NumExpansions);
 }
 }
 
 
 ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
 ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,

+ 10 - 7
lib/Sema/TreeTransform.h

@@ -3254,9 +3254,10 @@ public:
   ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
   ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
                                 BinaryOperatorKind Operator,
                                 BinaryOperatorKind Operator,
                                 SourceLocation EllipsisLoc, Expr *RHS,
                                 SourceLocation EllipsisLoc, Expr *RHS,
-                                SourceLocation RParenLoc) {
+                                SourceLocation RParenLoc,
+                                Optional<unsigned> NumExpansions) {
     return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,
     return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,
-                                      RHS, RParenLoc);
+                                      RHS, RParenLoc, NumExpansions);
   }
   }
 
 
   /// Build an empty C++1z fold-expression with the given operator.
   /// Build an empty C++1z fold-expression with the given operator.
@@ -11823,7 +11824,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
   // be expanded.
   // be expanded.
   bool Expand = true;
   bool Expand = true;
   bool RetainExpansion = false;
   bool RetainExpansion = false;
-  Optional<unsigned> NumExpansions;
+  Optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
+                     NumExpansions = OrigNumExpansions;
   if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
   if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
                                            Pattern->getSourceRange(),
                                            Pattern->getSourceRange(),
                                            Unexpanded,
                                            Unexpanded,
@@ -11852,7 +11854,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
 
 
     return getDerived().RebuildCXXFoldExpr(
     return getDerived().RebuildCXXFoldExpr(
         E->getBeginLoc(), LHS.get(), E->getOperator(), E->getEllipsisLoc(),
         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
   // The transform has determined that we should perform an elementwise
@@ -11873,7 +11875,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
 
 
     Result = getDerived().RebuildCXXFoldExpr(
     Result = getDerived().RebuildCXXFoldExpr(
         E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(),
         E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(),
-        Result.get(), E->getEndLoc());
+        Result.get(), E->getEndLoc(), OrigNumExpansions);
     if (Result.isInvalid())
     if (Result.isInvalid())
       return true;
       return true;
   }
   }
@@ -11890,7 +11892,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
       Result = getDerived().RebuildCXXFoldExpr(
       Result = getDerived().RebuildCXXFoldExpr(
           E->getBeginLoc(), LeftFold ? Result.get() : Out.get(),
           E->getBeginLoc(), LeftFold ? Result.get() : Out.get(),
           E->getOperator(), E->getEllipsisLoc(),
           E->getOperator(), E->getEllipsisLoc(),
-          LeftFold ? Out.get() : Result.get(), E->getEndLoc());
+          LeftFold ? Out.get() : Result.get(), E->getEndLoc(),
+          OrigNumExpansions);
     } else if (Result.isUsable()) {
     } else if (Result.isUsable()) {
       // We've got down to a single element; build a binary operator.
       // We've got down to a single element; build a binary operator.
       Result = getDerived().RebuildBinaryOperator(
       Result = getDerived().RebuildBinaryOperator(
@@ -11915,7 +11918,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
 
 
     Result = getDerived().RebuildCXXFoldExpr(
     Result = getDerived().RebuildCXXFoldExpr(
         E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(),
         E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(),
-        Out.get(), E->getEndLoc());
+        Out.get(), E->getEndLoc(), OrigNumExpansions);
     if (Result.isInvalid())
     if (Result.isInvalid())
       return true;
       return true;
   }
   }

+ 1 - 0
lib/Serialization/ASTReaderStmt.cpp

@@ -1810,6 +1810,7 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
   E->LParenLoc = ReadSourceLocation();
   E->LParenLoc = ReadSourceLocation();
   E->EllipsisLoc = ReadSourceLocation();
   E->EllipsisLoc = ReadSourceLocation();
   E->RParenLoc = ReadSourceLocation();
   E->RParenLoc = ReadSourceLocation();
+  E->NumExpansions = Record.readInt();
   E->SubExprs[0] = Record.readSubExpr();
   E->SubExprs[0] = Record.readSubExpr();
   E->SubExprs[1] = Record.readSubExpr();
   E->SubExprs[1] = Record.readSubExpr();
   E->Opcode = (BinaryOperatorKind)Record.readInt();
   E->Opcode = (BinaryOperatorKind)Record.readInt();

+ 1 - 0
lib/Serialization/ASTWriterStmt.cpp

@@ -1780,6 +1780,7 @@ void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
   Record.AddSourceLocation(E->LParenLoc);
   Record.AddSourceLocation(E->LParenLoc);
   Record.AddSourceLocation(E->EllipsisLoc);
   Record.AddSourceLocation(E->EllipsisLoc);
   Record.AddSourceLocation(E->RParenLoc);
   Record.AddSourceLocation(E->RParenLoc);
+  Record.push_back(E->NumExpansions);
   Record.AddStmt(E->SubExprs[0]);
   Record.AddStmt(E->SubExprs[0]);
   Record.AddStmt(E->SubExprs[1]);
   Record.AddStmt(E->SubExprs[1]);
   Record.push_back(E->Opcode);
   Record.push_back(E->Opcode);

+ 10 - 0
test/SemaTemplate/cxx1z-fold-expressions.cpp

@@ -92,3 +92,13 @@ template<typename ...T> constexpr auto spaceship3(T ...t) { return (t <=> ... <=
 template<typename ...T> constexpr auto binary_conditional1(T ...t) { return (t ?: ...); } // expected-error {{expected expression}}
 template<typename ...T> constexpr auto binary_conditional1(T ...t) { return (t ?: ...); } // expected-error {{expected expression}}
 template<typename ...T> constexpr auto binary_conditional2(T ...t) { return (... ?: t); } // expected-error {{expected expression}}
 template<typename ...T> constexpr auto binary_conditional2(T ...t) { return (... ?: t); } // expected-error {{expected expression}}
 template<typename ...T> constexpr auto binary_conditional3(T ...t) { return (t ?: ... ?: 0); } // expected-error {{expected expression}}
 template<typename ...T> constexpr auto binary_conditional3(T ...t) { return (t ?: ... ?: 0); } // expected-error {{expected expression}}
+
+namespace PR41845 {
+  template <int I> struct Constant {};
+
+  template <int... Is> struct Sum {
+    template <int... Js> 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}}
+}