[clang] [Clang][Sema] Warn on a function reference compared/converted to null (PR #204944)
Aditya Medhane via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 22 09:09:57 PDT 2026
https://github.com/flash1729 updated https://github.com/llvm/llvm-project/pull/204944
>From f1795ec1b1a655cd994d64a29bab59f17beab462 Mon Sep 17 00:00:00 2001
From: flash1729 <sherlockedaditya at gmail.com>
Date: Sun, 21 Jun 2026 00:35:37 +0530
Subject: [PATCH 1/3] [Clang][Sema] Warn on a function reference
compared/converted to null
Look through a reference-to-function in DiagnoseAlwaysNonNullPointer so
-Wtautological-pointer-compare and -Wpointer-bool-conversion fire for it,
as they already do for a bare function name.
Fixes #46362
---
clang/lib/Sema/SemaChecking.cpp | 9 +++++++++
clang/test/SemaCXX/warn-bool-conversion.cpp | 9 +++++++++
.../SemaCXX/warn-tautological-compare.cpp | 19 +++++++++++++++++++
3 files changed, 37 insertions(+)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b8a3f48a32f24..552f6842f8a5f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14256,6 +14256,11 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
}
QualType T = D->getType();
+ // A reference to a function is never null either; look through it.
+ const bool IsFunctionReference =
+ T->isReferenceType() && T->getPointeeType()->isFunctionType();
+ if (IsFunctionReference)
+ T = T->getPointeeType();
const bool IsArray = T->isArrayType();
const bool IsFunction = T->isFunctionType();
@@ -14294,6 +14299,10 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
if (!IsFunction)
return;
+ // The fix-it notes below only apply to a bare function name, not a reference.
+ if (IsFunctionReference)
+ return;
+
// Suggest '&' to silence the function warning.
Diag(E->getExprLoc(), diag::note_function_warning_silence)
<< FixItHint::CreateInsertion(E->getBeginLoc(), "&");
diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp
index 18c35776b17bc..8cf2a7a5816f5 100644
--- a/clang/test/SemaCXX/warn-bool-conversion.cpp
+++ b/clang/test/SemaCXX/warn-bool-conversion.cpp
@@ -132,6 +132,15 @@ void bar() {
b = S2::f4;
if (S2::f4) {}
}
+
+// GH46362: a reference to a function is never null, like a bare function name.
+void func_ref(void (&f)(), int *&ptr) {
+ bool b;
+ b = f; // expected-warning {{address of function 'f' will always evaluate to 'true'}}
+ if (f) {} // expected-warning {{address of function 'f' will always evaluate to 'true'}}
+ b = ptr;
+ if (ptr) {}
+}
}
namespace Array {
diff --git a/clang/test/SemaCXX/warn-tautological-compare.cpp b/clang/test/SemaCXX/warn-tautological-compare.cpp
index 7d5b4b14e9981..3028a9cf935cd 100644
--- a/clang/test/SemaCXX/warn-tautological-compare.cpp
+++ b/clang/test/SemaCXX/warn-tautological-compare.cpp
@@ -110,6 +110,25 @@ namespace FunctionCompare {
}
}
+namespace FunctionReferenceCompare {
+ // GH46362: a reference to a function is never null, like a bare function name.
+ // No fix-it note is emitted, since prefixing '&' would not silence it.
+ void test(void (&f)(), int *&ptr) {
+ if (f == 0) {}
+ // expected-warning at -1{{comparison of function 'f' equal to a null pointer is always false}}
+ if (f != 0) {}
+ // expected-warning at -1{{comparison of function 'f' not equal to a null pointer is always true}}
+ if (f == nullptr) {}
+ // expected-warning at -1{{comparison of function 'f' equal to a null pointer is always false}}
+ if (nullptr != f) {}
+ // expected-warning at -1{{comparison of function 'f' not equal to a null pointer is always true}}
+
+ // A reference to a pointer can be null: no warning.
+ if (ptr == nullptr) {}
+ if (ptr != nullptr) {}
+ }
+}
+
namespace PointerCompare {
extern int a __attribute__((weak));
int b;
>From f47eb3ff8418ae36e46c2f1cc2838070a6e70e34 Mon Sep 17 00:00:00 2001
From: flash1729 <sherlockedaditya at gmail.com>
Date: Sun, 21 Jun 2026 01:49:55 +0530
Subject: [PATCH 2/3] Update existing tests
---
clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp | 4 ++--
clang/test/SemaCXX/condition.cpp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
index 6744ce1cad174..1d18a667ead59 100644
--- a/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
@@ -45,7 +45,7 @@ void dependent(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
*ft;
+ft;
-ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
- !ft;
+ !ft; // expected-warning {{address of function 'ft' will always evaluate to 'true'}}
~ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
&ft;
++ft; // expected-error {{cannot increment value of type 'T ()'}}
@@ -62,4 +62,4 @@ void dependent(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
}
// Make sure we only emit diagnostics once.
-template void dependent(A t, A* pt, A B::* mpt, A(&ft)(), A(&at)[4]);
+template void dependent(A t, A* pt, A B::* mpt, A(&ft)(), A(&at)[4]); // expected-note {{in instantiation of function template specialization 'dependent<A, B>' requested here}}
diff --git a/clang/test/SemaCXX/condition.cpp b/clang/test/SemaCXX/condition.cpp
index db7694c7ee024..2526df22ec836 100644
--- a/clang/test/SemaCXX/condition.cpp
+++ b/clang/test/SemaCXX/condition.cpp
@@ -56,7 +56,7 @@ void test3() {
}
void test4(bool (&x)(void)) {
- while (x);
+ while (x); // expected-warning {{address of function 'x' will always evaluate to 'true'}}
}
template <class>
>From f64d8977361a95a7aa6bb2ebcf335a56b9bf2f78 Mon Sep 17 00:00:00 2001
From: flash1729 <sherlockedaditya at gmail.com>
Date: Mon, 22 Jun 2026 21:39:32 +0530
Subject: [PATCH 3/3] Update ReleaseNotes
---
clang/docs/ReleaseNotes.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7828135a6edbc..560de1f7d1e00 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -646,6 +646,11 @@ Improvements to Clang's diagnostics
- Diagnostics for the C++11 range-based for statement now report the correct
iterator type in notes for invalid iterator types.
+- ``-Wtautological-pointer-compare`` and ``-Wpointer-bool-conversion`` now
+ diagnose a reference to a function (e.g. of type ``void (&)()``) compared
+ against or converted to a null pointer, the same as a bare function name.
+ (#GH46362)
+
Improvements to Clang's time-trace
----------------------------------
More information about the cfe-commits
mailing list