From 7e677c542e4dd09c47adad8631093613d962da8a Mon Sep 17 00:00:00 2001 From: Zeeshan Siddiqui Date: Tue, 22 Jul 2025 06:37:54 +0000 Subject: [PATCH] [Sema] Make incorrect-logic operator check cast-agnostic The check for tautological comparisons (e.g. `x != 0 || x != 1`) failed on targets that support native scalar half precision because the operands differed only by an implicit `FloatingCast`. Extends Expr::isSameComparisonOperand() so that floating-rank promotions and lvalue-to-rvalue conversions no longer block the unreachable-code diagnostic on targets with native _Float16/__fp16. Updates existing test exercising both `__fp16` (promoted) and `_Float16` (native with +fullfp16) on x86-64 and AArch64. --- clang/docs/ReleaseNotes.rst | 5 +++ clang/lib/AST/Expr.cpp | 14 ++++++-- clang/test/Sema/warn-unreachable_crash.cpp | 41 +++++++++++++++------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9d9a0008e0001..4a2edae7509de 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -134,6 +134,11 @@ Bug Fixes in This Version ------------------------- - Fix a crash when marco name is empty in ``#pragma push_macro("")`` or ``#pragma pop_macro("")``. (#GH149762). +- `-Wunreachable-code`` now diagnoses tautological or contradictory + comparisons such as ``x != 0 || x != 1.0`` and ``x == 0 && x == 1.0`` on + targets that treat ``_Float16``/``__fp16`` as native scalar types. Previously + the warning was silently lost because the operands differed only by an implicit + cast chain. (#GH149967). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d85655b1596f4..cd9672d32a013 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4233,8 +4233,15 @@ bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { // template parameters. const auto *DRE1 = cast(E1); const auto *DRE2 = cast(E2); - return DRE1->isPRValue() && DRE2->isPRValue() && - DRE1->getDecl() == DRE2->getDecl(); + + if (DRE1->getDecl() != DRE2->getDecl()) + return false; + + if ((DRE1->isPRValue() && DRE2->isPRValue()) || + (DRE1->isLValue() && DRE2->isLValue())) + return true; + + return false; } case ImplicitCastExprClass: { // Peel off implicit casts. @@ -4244,7 +4251,8 @@ bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { if (!ICE1 || !ICE2) return false; if (ICE1->getCastKind() != ICE2->getCastKind()) - return false; + return isSameComparisonOperand(ICE1->IgnoreParenImpCasts(), + ICE2->IgnoreParenImpCasts()); E1 = ICE1->getSubExpr()->IgnoreParens(); E2 = ICE2->getSubExpr()->IgnoreParens(); // The final cast must be one of these types. diff --git a/clang/test/Sema/warn-unreachable_crash.cpp b/clang/test/Sema/warn-unreachable_crash.cpp index 628abcc83f810..1955c2c2547f5 100644 --- a/clang/test/Sema/warn-unreachable_crash.cpp +++ b/clang/test/Sema/warn-unreachable_crash.cpp @@ -1,16 +1,33 @@ -// RUN: %clang_cc1 -verify -Wunreachable-code %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -verify -Wunreachable-code %s +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -target-feature +fullfp16 -verify -Wunreachable-code %s +// REQUIRES: aarch64-registered-target -// 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}} +// ======= __fp16 version ======= +static void test_fp16(__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; +static void test_fp16_b(__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; +} + +// ======= _Float16 version ======= +static void test_f16(_Float16 &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 test_f16_b(_Float16 &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; }