[clang] 23b2045 - [clang] p2085 out-of-class comparison operator defaulting

Nathan Sidwell via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 20 08:48:23 PST 2021


Author: Nathan Sidwell
Date: 2021-12-20T08:47:54-08:00
New Revision: 23b2045eef45884566722d06f3e09224a0f6dc6c

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

LOG: [clang] p2085 out-of-class comparison operator defaulting

Commit 5fbe21a7748f missed committing the correct checking of
out-of-class comparision operator argument types.  These are they,
from the originally posted diff.

Reviewed By: mizvekov

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

Added: 
    

Modified: 
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CXX/class/class.compare/class.compare.default/p1.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 119cdf2a3d3c0..01f0079198c74 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8531,8 +8531,6 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
             QualType PlainTy = Context.getRecordType(RD);
             QualType RefTy =
                 Context.getLValueReferenceType(PlainTy.withConst());
-            if (IsMethod)
-              PlainTy = QualType();
             Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
                 << int(DCK) << ParmTy << RefTy << int(!IsMethod) << PlainTy
                 << Param->getSourceRange();
@@ -17266,10 +17264,13 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
   // that we've marked it as defaulted.
   FD->setWillHaveBody(false);
 
-  // If this is a comparison's defaulted definition within the record, do
-  // the checking when the record is complete.
-  if (DefKind.isComparison() && isa<CXXRecordDecl>(FD->getLexicalDeclContext()))
-    return;
+  if (DefKind.isComparison()) {
+    // If this comparison's defaulting occurs within the definition of its
+    // lexical class context, we have to do the checking when complete.
+    if (auto const *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()))
+      if (!RD->isCompleteDefinition())
+        return;
+  }
 
   // If this member fn was defaulted on its first declaration, we will have
   // already performed the checking in CheckCompletedCXXClass. Such a

diff  --git a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
index 136afd8996432..4bfd27461ed5e 100644
--- a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
+++ b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
@@ -115,6 +115,28 @@ namespace LookupContext {
   }
 }
 
+namespace evil1 {
+template <class T> struct Bad {
+  // expected-error at +1{{found 'const float &'}}
+  bool operator==(T const &) const = default;
+  Bad(int = 0);
+};
+
+template <class T> struct Weird {
+  // expected-error at +1{{'float' cannot be used prior to '::'}}
+  bool operator==(typename T::Weird_ const &) const = default;
+  Weird(int = 0);
+};
+
+struct evil {
+  using Weird_ = Weird<evil>;
+};
+template struct Bad<float>;   // expected-note{{evil1::Bad<float>' requested}}
+template struct Weird<float>; // expected-note{{evil1::Weird<float>' requested}}
+template struct Weird<evil>;
+
+} // namespace evil1
+
 namespace P1946 {
   struct A {
     friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}}
@@ -161,5 +183,40 @@ enum e {};
 bool operator==(e, int) = default; // expected-error{{expected class or reference to a constant class}}
 
 bool operator==(e *, int *) = default; // expected-error{{must have at least one}}
-
 } // namespace p2085
+
+namespace p2085_2 {
+template <class T> struct S6 {
+  // expected-error at +2{{found 'const int &'}}
+  // expected-error at +1{{found 'const float &'}}
+  bool operator==(T const &) const;
+};
+template <class T> bool S6<T>::operator==(T const &) const = default;
+
+template struct S6<int>; // expected-note{{S6<int>::operator==' requested}}
+
+void f1() {
+  S6<float> a;
+  (void)(a == 0); // expected-note{{S6<float>::operator==' requested}}
+}
+
+template <class T> struct S7 {
+  // expected-error at +2{{'float' cannot be used}}
+  // expected-error at +1{{'int' cannot be used}}
+  bool operator==(typename T::S7_ const &) const;
+  S7(int = 0);
+};
+template <class T> bool S7<T>::operator==(typename T::S7_ const &) const = default;
+
+struct evil {
+  using S7_ = S7<evil>;
+};
+template struct S7<float>; // expected-note{{S7<float>' requested}}
+
+void f2() {
+  S7<int> a; // expected-note{{S7<int>' requested}}
+  S7<evil> b;
+  (void)(a == 0); // expected-error{{invalid operands}}
+  (void)(b == 0);
+}
+} // namespace p2085_2


        


More information about the cfe-commits mailing list