Author: Aditya Medhane
Date: 2026-07-06T13:39:31+02:00
New Revision: fb1de34e8db8d11c764c7ff422879f923554cbd9

URL: 
https://github.com/llvm/llvm-project/commit/fb1de34e8db8d11c764c7ff422879f923554cbd9
DIFF: 
https://github.com/llvm/llvm-project/commit/fb1de34e8db8d11c764c7ff422879f923554cbd9.diff

LOG: [Clang][Sema] Warn on a function reference compared/converted to null 
(#204944)

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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.md
    clang/lib/Sema/SemaChecking.cpp
    clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
    clang/test/SemaCXX/condition.cpp
    clang/test/SemaCXX/warn-bool-conversion.cpp
    clang/test/SemaCXX/warn-tautological-compare.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b7142ecb072ff..ea79b3b1b3692 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -686,6 +686,11 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
   by the kernel, so setting them is almost always a typo (matching the
   bionic libc `diagnose_if` check).
 
+- `-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
 
 ### Improvements to Coverage Mapping

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 01b1f4c26f017..965b92a2b5874 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14398,6 +14398,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();
 
@@ -14433,7 +14438,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
   Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
                                 << Range << IsEqual;
 
-  if (!IsFunction)
+  // The fix-it notes below only apply to a bare function name, not a 
reference.
+  if (!IsFunction || IsFunctionReference)
     return;
 
   // Suggest '&' to silence the function warning.

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>

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@-1{{comparison of function 'f' equal to a null pointer 
is always false}}
+    if (f != 0) {}
+    // expected-warning@-1{{comparison of function 'f' not equal to a null 
pointer is always true}}
+    if (f == nullptr) {}
+    // expected-warning@-1{{comparison of function 'f' equal to a null pointer 
is always false}}
+    if (nullptr != f) {}
+    // expected-warning@-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;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to