-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][CFG] Fix assertion failure in checkIncorrectLogicOperator #142897
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
base: main
Are you sure you want to change the base?
Conversation
`checkIncorrectLogicOperator` checks if an expression, for example `x != 0 || x != 1.0`, is always true or false by comparing the two literals `0` and `1.0`. But in case `x` is a 16-bit float, the two literals have distinct types---16-bit float and double, respectively. Directly comparing `APValue`s extracted from the two literals results in an assertion failure because of their distinct types. This commit fixes the issue by doing a conversion from the "smaller" one to the "bigger" one. The two literals must be compatible because both of them are comparing with `x`. rdar://152456316
@llvm/pr-subscribers-clang-analysis Author: Ziqing Luo (ziqingluo-90) Changes
This commit fixes the issue by doing a conversion from the "smaller" one to the "bigger" one. The two literals must be compatible because both of them are comparing with rdar://152456316 Full diff: https://github.com/llvm/llvm-project/pull/142897.diff 2 Files Affected:
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 7f37a8b18d46e..c9610cc2888ad 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1261,6 +1261,28 @@ class CFGBuilder {
L2Result.Val.getKind() == APValue::Float) {
llvm::APFloat L1 = L1Result.Val.getFloat();
llvm::APFloat L2 = L2Result.Val.getFloat();
+ // Note that L1 and L2 do not necessarily have the same type. For example
+ // `x != 0 || x != 1.0`, if `x` is a float16, the two literals `0` and
+ // `1.0` are float16 and double respectively. In this case, we should do
+ // a conversion before comparing L1 and L2. Their types must be
+ // compatible since they are comparing with the same DRE.
+ int8_t Order = Context->getFloatingTypeOrder(NumExpr1->getType(),
+ NumExpr2->getType());
+ bool convertLoseInfo = false;
+
+ if (Order > 0) {
+ // type rank L1 > L2:
+ if (L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
+ &convertLoseInfo))
+ return {};
+ } else if (Order < 0)
+ // type rank L1 < L2:
+ if (L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
+ &convertLoseInfo))
+ return {};
+ if (convertLoseInfo)
+ return {}; // If the conversion loses info, bail
+
llvm::APFloat MidValue = L1;
MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
MidValue.divide(llvm::APFloat(MidValue.getSemantics(), "2.0"),
diff --git a/clang/test/Sema/warn-unreachable_crash.cpp b/clang/test/Sema/warn-unreachable_crash.cpp
new file mode 100644
index 0000000000000..7b23f30c6a214
--- /dev/null
+++ b/clang/test/Sema/warn-unreachable_crash.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify -Wunreachable-code %s
+
+static void test(__fp16& x) {
+ if (x != 0 || x != 1.0) { // expected-note{{}}
+ x = 0.9;
+ } else
+ x = 0.8; // expected-warning{{code will never be executed}}
+}
|
@llvm/pr-subscribers-clang Author: Ziqing Luo (ziqingluo-90) Changes
This commit fixes the issue by doing a conversion from the "smaller" one to the "bigger" one. The two literals must be compatible because both of them are comparing with rdar://152456316 Full diff: https://github.com/llvm/llvm-project/pull/142897.diff 2 Files Affected:
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 7f37a8b18d46e..c9610cc2888ad 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1261,6 +1261,28 @@ class CFGBuilder {
L2Result.Val.getKind() == APValue::Float) {
llvm::APFloat L1 = L1Result.Val.getFloat();
llvm::APFloat L2 = L2Result.Val.getFloat();
+ // Note that L1 and L2 do not necessarily have the same type. For example
+ // `x != 0 || x != 1.0`, if `x` is a float16, the two literals `0` and
+ // `1.0` are float16 and double respectively. In this case, we should do
+ // a conversion before comparing L1 and L2. Their types must be
+ // compatible since they are comparing with the same DRE.
+ int8_t Order = Context->getFloatingTypeOrder(NumExpr1->getType(),
+ NumExpr2->getType());
+ bool convertLoseInfo = false;
+
+ if (Order > 0) {
+ // type rank L1 > L2:
+ if (L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
+ &convertLoseInfo))
+ return {};
+ } else if (Order < 0)
+ // type rank L1 < L2:
+ if (L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
+ &convertLoseInfo))
+ return {};
+ if (convertLoseInfo)
+ return {}; // If the conversion loses info, bail
+
llvm::APFloat MidValue = L1;
MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
MidValue.divide(llvm::APFloat(MidValue.getSemantics(), "2.0"),
diff --git a/clang/test/Sema/warn-unreachable_crash.cpp b/clang/test/Sema/warn-unreachable_crash.cpp
new file mode 100644
index 0000000000000..7b23f30c6a214
--- /dev/null
+++ b/clang/test/Sema/warn-unreachable_crash.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify -Wunreachable-code %s
+
+static void test(__fp16& x) {
+ if (x != 0 || x != 1.0) { // expected-note{{}}
+ x = 0.9;
+ } else
+ x = 0.8; // expected-warning{{code will never be executed}}
+}
|
Godbolt example: https://godbolt.org/z/6dv3Kearx CC @YutongZhuu as this issue was first introduced in YutongZhuu@9ae3368 |
clang/lib/Analysis/CFG.cpp
Outdated
// `1.0` are float16 and double respectively. In this case, we should do | ||
// a conversion before comparing L1 and L2. Their types must be | ||
// compatible since they are comparing with the same DRE. | ||
int8_t Order = Context->getFloatingTypeOrder(NumExpr1->getType(), |
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.
int8_t Order = Context->getFloatingTypeOrder(NumExpr1->getType(), | |
int Order = Context->getFloatingTypeSemanticOrder(NumExpr1->getType(), |
Why we use int8_t here? the return type of getFloatingTypeOrder
is int.
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.
good point, I initially thought it just returns -1,0, or 1 but it's not the case.
clang/lib/Analysis/CFG.cpp
Outdated
if (L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven, | ||
&convertLoseInfo)) | ||
return {}; | ||
if (convertLoseInfo) |
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.
Seems we check APFloat::opStatus is enough. We already ignore loseInfo in constant evaluator
llvm-project/clang/lib/AST/ExprConstant.cpp
Line 2871 in f871466
St = Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), RM, &ignored); |
clang/lib/Analysis/CFG.cpp
Outdated
|
||
if (Order > 0) { | ||
// type rank L1 > L2: | ||
if (L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven, |
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.
I think useif (L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven, &convertLoseInfo) != APFloat::opOK)
more clear, WDYT?
Thank you working on this! Overall LGTM! But I don't think I'm qualified to make the final sign. CC @steakhal. |
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.
I don't think I have much to say. I never really touched floating-point stuff.
I left the comments I had while reading though.
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.
Thanks, LGTM!
checkIncorrectLogicOperator
checks if an expression, for examplex != 0 || x != 1.0
, is always true or false by comparing the two literals0
and1.0
. But in casex
is a 16-bit float, the two literals have distinct types---16-bit float and double, respectively. Directly comparingAPValue
s extracted from the two literals results in an assertion failure because of their distinct types.This commit fixes the issue by doing a conversion from the "smaller" one to the "bigger" one. The two literals must be compatible because both of them are comparing with
x
.rdar://152456316