forked from OSchip/llvm-project
PR41845: Detect and reject mismatched inner/outer pack expansion sizes
in fold expressions rather than crashing. llvm-svn: 360563
This commit is contained in:
parent
1effa6c665
commit
c7214f6510
|
@ -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<unsigned> 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<unsigned> getNumExpansions() const {
|
||||
if (NumExpansions)
|
||||
return NumExpansions - 1;
|
||||
return None;
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; }
|
||||
|
||||
SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
|
||||
|
|
|
@ -5204,7 +5204,8 @@ public:
|
|||
ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
|
||||
BinaryOperatorKind Operator,
|
||||
SourceLocation EllipsisLoc, Expr *RHS,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc,
|
||||
Optional<unsigned> NumExpansions);
|
||||
ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
|
||||
BinaryOperatorKind Operator);
|
||||
|
||||
|
|
|
@ -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<unsigned> NumExpansions) {
|
||||
return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
|
||||
Operator, EllipsisLoc, RHS, RParenLoc);
|
||||
Operator, EllipsisLoc, RHS, RParenLoc,
|
||||
NumExpansions);
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
|
||||
|
|
|
@ -3254,9 +3254,10 @@ public:
|
|||
ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
|
||||
BinaryOperatorKind Operator,
|
||||
SourceLocation EllipsisLoc, Expr *RHS,
|
||||
SourceLocation RParenLoc) {
|
||||
SourceLocation RParenLoc,
|
||||
Optional<unsigned> 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<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
|
|||
// be expanded.
|
||||
bool Expand = true;
|
||||
bool RetainExpansion = false;
|
||||
Optional<unsigned> NumExpansions;
|
||||
Optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
|
||||
NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
|
||||
Pattern->getSourceRange(),
|
||||
Unexpanded,
|
||||
|
@ -11852,7 +11854,7 @@ TreeTransform<Derived>::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<Derived>::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<Derived>::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<Derived>::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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_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}}
|
||||
|
||||
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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue