-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[Clang] Warning as error for fold expressions over comparison operators #136836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8d70f4b
7e53392
7c61d91
5a2297b
2b8e3b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14918,8 +14918,8 @@ static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, | |
| } | ||
|
|
||
| ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, | ||
| BinaryOperatorKind Opc, | ||
| Expr *LHSExpr, Expr *RHSExpr) { | ||
| BinaryOperatorKind Opc, Expr *LHSExpr, | ||
| Expr *RHSExpr, bool ForFoldExpression) { | ||
| if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) { | ||
| // The syntax only allows initializer lists on the RHS of assignment, | ||
| // so we don't need to worry about accepting invalid code for | ||
|
|
@@ -15050,7 +15050,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, | |
| ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); | ||
|
|
||
| if (const auto *BI = dyn_cast<BinaryOperator>(LHSExpr); | ||
| BI && BI->isComparisonOp()) | ||
| !ForFoldExpression && BI && BI->isComparisonOp()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The right fold cases are handled by this branch, right? So shall we rename ForFoldExpression to ForLeftFold or something?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's just a side effect of looking at the LHS first - I don't think the distinction matters here |
||
| Diag(OpLoc, diag::warn_consecutive_comparison) | ||
| << BI->getOpcodeStr() << BinaryOperator::getOpcodeStr(Opc); | ||
|
|
||
|
|
@@ -15460,8 +15460,8 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, | |
| } | ||
|
|
||
| ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, | ||
| BinaryOperatorKind Opc, | ||
| Expr *LHSExpr, Expr *RHSExpr) { | ||
| BinaryOperatorKind Opc, Expr *LHSExpr, | ||
| Expr *RHSExpr, bool ForFoldExpression) { | ||
| ExprResult LHS, RHS; | ||
| std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); | ||
| if (!LHS.isUsable() || !RHS.isUsable()) | ||
|
|
@@ -15535,7 +15535,8 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, | |
| LHSExpr->getType()->isOverloadableType())) | ||
| return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); | ||
|
|
||
| return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); | ||
| return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr, | ||
| ForFoldExpression); | ||
| } | ||
|
|
||
| // Don't resolve overloads if the other type is overloadable. | ||
|
|
@@ -15599,7 +15600,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, | |
| } | ||
|
|
||
| // Build a built-in binary operation. | ||
| return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); | ||
| return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr, ForFoldExpression); | ||
| } | ||
|
|
||
| static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,3 +132,30 @@ bool f(); | |
| template <typename... T> | ||
| void g(bool = (f<T>() || ...)); | ||
| } | ||
|
|
||
|
|
||
| namespace comparison_warning { | ||
| struct S { | ||
| bool operator<(const S&) const; | ||
| bool operator<(int) const; | ||
| bool operator==(const S&) const; | ||
| }; | ||
|
|
||
| template <typename...T> | ||
| void f(T... ts) { | ||
| (void)(ts == ...); | ||
| // expected-error@-1 2{{comparison in fold expression would evaluate to '(X == Y) == Z'}} | ||
| (void)(ts < ...); | ||
| // expected-error@-1 2{{comparison in fold expression would evaluate to '(X < Y) < Z'}} | ||
| (void)(... < ts); | ||
| // expected-error@-1 2{{comparison in fold expression would evaluate to '(X < Y) < Z'}} | ||
| } | ||
|
|
||
| void test() { | ||
| f(0, 1, 2); // expected-note{{in instantiation}} | ||
| f(0, 1); // expected-note{{in instantiation}} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm. It looks strange to me if we warn for '0 < 1'
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is intended -, ideally, we would even warn when |
||
| f(S{}, S{}); | ||
| f(0); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you test |
||
| } | ||
|
|
||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better to print out the expression than X, Y, Z
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I'm thinking if there's a case where it actually evaluates to
X %0 (Y %0 Z)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We added that discussion for the previous PR, we concluded it was really not useful!