[clang] 7ddd15c - [clang] Exclude function pointers on DefaultedComparisonAnalyzer

Matheus Izvekov via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 18 04:07:58 PDT 2021


Author: Matheus Izvekov
Date: 2021-06-18T13:07:47+02:00
New Revision: 7ddd15cd5dea76a19a9c5315e2a9903d74a49be8

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

LOG: [clang] Exclude function pointers on DefaultedComparisonAnalyzer

This implements a more comprehensive fix than was done at D95409.
Instead of excluding just function pointer subobjects, we also
exclude any user-defined function pointer conversion operators.

Signed-off-by: Matheus Izvekov <mizvekov at gmail.com>

Reviewed By: rsmith

Differential Revision: https://reviews.llvm.org/D103855

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CXX/class/class.compare/class.spaceship/p2.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c07e6f9d7421a..33aa5d0483e9c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9143,6 +9143,9 @@ def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
   "%select{|member|base class}0 %1 declared here">;
 def note_defaulted_comparison_cannot_deduce_callee : Note<
   "selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
+def note_defaulted_comparison_selected_invalid : Note<
+  "would compare %select{|member|base class}0 %1 "
+  "as %2, which does not support relational comparisons">;
 def err_incorrect_defaulted_comparison_constexpr : Error<
   "defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
   "three-way comparison operator}0 "

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d39837d277045..5109f1e877a26 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7749,16 +7749,11 @@ class DefaultedComparisonAnalyzer
 
     if (Args[0]->getType()->isOverloadableType())
       S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
-    else if (OO == OO_EqualEqual ||
-             !Args[0]->getType()->isFunctionPointerType()) {
+    else
       // FIXME: We determine whether this is a valid expression by checking to
       // see if there's a viable builtin operator candidate for it. That isn't
       // really what the rules ask us to do, but should give the right results.
-      //
-      // Note that the builtin operator for relational comparisons on function
-      // pointers is the only known case which cannot be used.
       S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet);
-    }
 
     Result R;
 
@@ -7802,11 +7797,14 @@ class DefaultedComparisonAnalyzer
           return Result::deleted();
       }
 
-      // C++2a [class.compare.default]p3 [P2002R0]:
-      //   A defaulted comparison function is constexpr-compatible if [...]
-      //   no overlod resolution performed [...] results in a non-constexpr
-      //   function.
+      bool NeedsDeducing =
+          OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType();
+
       if (FunctionDecl *BestFD = Best->Function) {
+        // C++2a [class.compare.default]p3 [P2002R0]:
+        //   A defaulted comparison function is constexpr-compatible if
+        //   [...] no overlod resolution performed [...] results in a
+        //   non-constexpr function.
         assert(!BestFD->isDeleted() && "wrong overload resolution result");
         // If it's not constexpr, explain why not.
         if (Diagnose == ExplainConstexpr && !BestFD->isConstexpr()) {
@@ -7819,10 +7817,8 @@ class DefaultedComparisonAnalyzer
           return Result::deleted();
         }
         R.Constexpr &= BestFD->isConstexpr();
-      }
 
-      if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
-        if (auto *BestFD = Best->Function) {
+        if (NeedsDeducing) {
           // If any callee has an undeduced return type, deduce it now.
           // FIXME: It's not clear how a failure here should be handled. For
           // now, we produce an eager diagnostic, because that is forward
@@ -7848,10 +7844,9 @@ class DefaultedComparisonAnalyzer
             }
             return Result::deleted();
           }
-          if (auto *Info = S.Context.CompCategories.lookupInfoForType(
-              BestFD->getCallResultType())) {
-            R.Category = Info->Kind;
-          } else {
+          auto *Info = S.Context.CompCategories.lookupInfoForType(
+              BestFD->getCallResultType());
+          if (!Info) {
             if (Diagnose == ExplainDeleted) {
               S.Diag(Subobj.Loc, diag::note_defaulted_comparison_cannot_deduce)
                   << Subobj.Kind << Subobj.Decl
@@ -7862,12 +7857,25 @@ class DefaultedComparisonAnalyzer
             }
             return Result::deleted();
           }
-        } else {
-          QualType T = Best->BuiltinParamTypes[0];
-          assert(T == Best->BuiltinParamTypes[1] &&
-                 "builtin comparison for 
diff erent types?");
-          assert(Best->BuiltinParamTypes[2].isNull() &&
-                 "invalid builtin comparison");
+          R.Category = Info->Kind;
+        }
+      } else {
+        QualType T = Best->BuiltinParamTypes[0];
+        assert(T == Best->BuiltinParamTypes[1] &&
+               "builtin comparison for 
diff erent types?");
+        assert(Best->BuiltinParamTypes[2].isNull() &&
+               "invalid builtin comparison");
+
+        // The builtin operator for relational comparisons on function
+        // pointers is the only known case which cannot be used.
+        if (OO != OO_EqualEqual && T->isFunctionPointerType()) {
+          if (Diagnose == ExplainDeleted)
+            S.Diag(Subobj.Loc, diag::note_defaulted_comparison_selected_invalid)
+                << Subobj.Kind << Subobj.Decl << T;
+          return Result::deleted();
+        }
+
+        if (NeedsDeducing) {
           Optional<ComparisonCategoryType> Cat =
               getComparisonCategoryForBuiltinCmp(T);
           assert(Cat && "no category for builtin comparison?");

diff  --git a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
index 47b14cb5f9616..01fff692c0c85 100644
--- a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
+++ b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
@@ -159,7 +159,7 @@ namespace BadDeducedType {
 namespace PR48856 {
   struct A {
     auto operator<=>(const A &) const = default; // expected-warning {{implicitly deleted}}
-    void (*x)();                                 // expected-note {{because there is no viable three-way comparison function for member 'x'}}
+    void (*x)();                                 // expected-note {{does not support relational comparisons}}
   };
 
   struct B {
@@ -191,4 +191,13 @@ namespace PR50591 {
     a2 f;
   };
   std::partial_ordering cmp_b2 = b2() <=> b2();
+
+  struct a3 {
+    using fp = void (*)();
+    operator fp() const;
+  };
+  struct b3 {
+    auto operator<=>(b3 const &) const = default; // expected-warning {{implicitly deleted}}
+    a3 f; // expected-note {{would compare member 'f' as 'void (*)()', which does not support relational comparisons}}
+  };
 }


        


More information about the cfe-commits mailing list