[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