diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -455,6 +455,8 @@ - Add ``-Wreturn-local-addr``, a GCC alias for ``-Wreturn-stack-address``. - Clang now suppresses ``-Wlogical-op-parentheses`` on ``(x && a || b)`` and ``(a || b && x)`` only when ``x`` is a string literal. +- Add ``-Wcompare-function-pointers`` to warn about comparisons that may have their behavior + change when enabling the identical code folding optimization feature of some linkers. Non-comprehensive list of changes in this release ------------------------------------------------- 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 @@ -564,6 +564,7 @@ def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; def OrderedCompareFunctionPointers : DiagGroup<"ordered-compare-function-pointers">; +def CompareFunctionPointers : DiagGroup<"compare-function-pointers", [OrderedCompareFunctionPointers]>; def PackedNonPod : DiagGroup<"packed-non-pod">; def Packed : DiagGroup<"packed", [PackedNonPod]>; def Padded : DiagGroup<"padded">; 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 @@ -7009,6 +7009,10 @@ "%0 is %select{|in}2complete and " "%1 is %select{|in}3complete">, InGroup; +def warn_typecheck_comparison_of_function_pointers : Warning< + "distinct function pointers (%0 and %1) may compare equal " + "when using identical code folding">, + 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,12 @@ LHS.get()->getSourceRange()); } + if (!IsOrdered && LHSType->isFunctionPointerType() && + RHSType->isFunctionPointerType() && !LHSIsNull && !RHSIsNull) + Diag(Loc, diag::warn_typecheck_comparison_of_function_pointers) + << LHSType << RHSType + << 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,8 +6,8 @@ extern fp0_t a, b; extern fp1_t c; -bool eq0 = a == b; -bool ne0 = a != b; +bool eq0 = a == b; // expected-warning {{distinct function pointers ('fp0_t' (aka 'void (*)()') and 'fp0_t')}} +bool ne0 = a != b; // expected-warning {{distinct 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}} @@ -15,7 +15,9 @@ auto tw0 = a <=> b; // expected-error {{ordered comparison of function pointers}} bool eq1 = a == c; // expected-error {{comparison of distinct pointer types}} + // expected-warning@-1 {{distinct function pointers ('fp0_t' (aka 'void (*)()') and 'fp1_t' (aka 'int (*)()'))}} bool ne1 = a != c; // expected-error {{comparison of distinct pointer types}} + // expected-warning@-1 {{distinct 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}}