diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -561,6 +561,7 @@ def UnderalignedExceptionObject : DiagGroup<"underaligned-exception-object">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; +def CompareFunctionPointers : DiagGroup<"compare-function-pointers">; def OrderedCompareFunctionPointers : DiagGroup<"ordered-compare-function-pointers">; def PackedNonPod : DiagGroup<"packed-non-pod">; def Packed : DiagGroup<"packed", [PackedNonPod]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7002,6 +7002,9 @@ "%0 is %select{|in}2complete and " "%1 is %select{|in}3complete">, InGroup; +def warn_typecheck_comparison_of_function_pointers : Warning< + "comparison of function pointers (%0 and %1)">, + InGroup, DefaultIgnore; def warn_typecheck_ordered_comparison_of_function_pointers : Warning< "ordered comparison of function pointers (%0 and %1)">, InGroup; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12711,6 +12711,13 @@ LHS.get()->getSourceRange()); } + if (!IsOrdered && LHSType->isFunctionPointerType() && + RHSType->isFunctionPointerType() && !LHSIsNull && !RHSIsNull) { + Diag(Loc, diag::warn_typecheck_comparison_of_function_pointers) + << LHSType << 0 + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + } + if (IsOrdered && LHSType->isFunctionPointerType() && RHSType->isFunctionPointerType()) { // Valid unless a relational comparison of function pointers diff --git a/clang/test/SemaCXX/compare-function-pointer.cpp b/clang/test/SemaCXX/compare-function-pointer.cpp --- a/clang/test/SemaCXX/compare-function-pointer.cpp +++ b/clang/test/SemaCXX/compare-function-pointer.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -Wcompare-function-pointers %s using fp0_t = void (*)(); using fp1_t = int (*)(); @@ -6,16 +6,16 @@ extern fp0_t a, b; extern fp1_t c; -bool eq0 = a == b; -bool ne0 = a != b; +bool eq0 = a == b; // expected-warning {{comparison of function pointers}} +bool ne0 = a != b; // expected-warning {{comparison of function pointers}} bool lt0 = a < b; // expected-warning {{ordered comparison of function pointers ('fp0_t' (aka 'void (*)()') and 'fp0_t')}} bool le0 = a <= b; // expected-warning {{ordered comparison of function pointers}} bool gt0 = a > b; // expected-warning {{ordered comparison of function pointers}} bool ge0 = a >= b; // expected-warning {{ordered comparison of function pointers}} auto tw0 = a <=> b; // expected-error {{ordered comparison of function pointers}} -bool eq1 = a == c; // expected-error {{comparison of distinct pointer types}} -bool ne1 = a != c; // expected-error {{comparison of distinct pointer types}} +bool eq1 = a == c; // expected-error {{comparison of distinct pointer types}} expected-warning {{comparison of function pointers}} +bool ne1 = a != c; // expected-error {{comparison of distinct pointer types}} expected-warning {{comparison of function pointers}} bool lt1 = a < c; // expected-warning {{ordered comparison of function pointers ('fp0_t' (aka 'void (*)()') and 'fp1_t' (aka 'int (*)()'))}} // expected-error@-1 {{comparison of distinct pointer types}} bool le1 = a <= c; // expected-warning {{ordered comparison of function pointers}}