[clang][CFG] Fix assertion failure in checkIncorrectLogicOperator (#142897)

`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
This commit is contained in:
Ziqing Luo 2025-06-10 11:54:01 +08:00 committed by GitHub
parent 9a894ae794
commit b9d41328c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 0 deletions

View File

@ -1261,6 +1261,28 @@ private:
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.
int Order = Context->getFloatingTypeSemanticOrder(NumExpr1->getType(),
NumExpr2->getType());
bool Ignored = false;
if (Order > 0) {
// type rank L1 > L2:
if (llvm::APFloat::opOK !=
L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
&Ignored))
return {};
} else if (Order < 0)
// type rank L1 < L2:
if (llvm::APFloat::opOK !=
L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
&Ignored))
return {};
llvm::APFloat MidValue = L1;
MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
MidValue.divide(llvm::APFloat(MidValue.getSemantics(), "2.0"),

View File

@ -0,0 +1,16 @@
// RUN: %clang_cc1 -verify -Wunreachable-code %s
// Previously this test will crash
static void test(__fp16& x) {
if (x != 0 || x != 1.0) { // expected-note{{}} no-crash
x = 0.9;
} else
x = 0.8; // expected-warning{{code will never be executed}}
}
static void test2(__fp16& x) {
if (x != 1 && x == 1.0) { // expected-note{{}} no-crash
x = 0.9; // expected-warning{{code will never be executed}}
} else
x = 0.8;
}