Author: Richard Smith Date: 2019-12-10T19:54:35-08:00 New Revision: ffe612922cb5aa2767c79d47a1b162811a08583f
URL: https://github.com/llvm/llvm-project/commit/ffe612922cb5aa2767c79d47a1b162811a08583f DIFF: https://github.com/llvm/llvm-project/commit/ffe612922cb5aa2767c79d47a1b162811a08583f.diff LOG: [c++20] Implement P1946R0: allow defaulted comparisons to take their arguments by value. Added: Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaDeclCXX.cpp clang/test/CXX/class/class.compare/class.compare.default/p1.cpp clang/test/CXX/class/class.compare/class.eq/p3.cpp clang/www/cxx_status.html Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4eec4b066ae5..423ccbd293d2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8194,7 +8194,10 @@ def err_defaulted_comparison_out_of_class : Error< "definition">; def err_defaulted_comparison_param : Error< "invalid parameter type for defaulted %sub{select_defaulted_comparison_kind}0" - "% diff {; found $, expected $|}1,2">; + "; found %1, expected %2%select{| or %4}3">; +def err_defaulted_comparison_param_mismatch : Error< + "parameters for defaulted %sub{select_defaulted_comparison_kind}0 " + "must have the same type% diff { (found $ vs $)|}1,2">; def err_defaulted_comparison_non_const : Error< "defaulted member %sub{select_defaulted_comparison_kind}0 must be " "const-qualified">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 365286097699..5373bb422ad6 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7921,22 +7921,41 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // non-template function declared in the member-specification of C that is // -- a non-static const member of C having one parameter of type // const C&, or - // -- a friend of C having two parameters of type const C&. - QualType ExpectedParmType = - Context.getLValueReferenceType(Context.getRecordType(RD).withConst()); + // -- a friend of C having two parameters of type const C& or two + // parameters of type C. + QualType ExpectedParmType1 = Context.getRecordType(RD); + QualType ExpectedParmType2 = + Context.getLValueReferenceType(ExpectedParmType1.withConst()); + if (isa<CXXMethodDecl>(FD)) + ExpectedParmType1 = ExpectedParmType2; for (const ParmVarDecl *Param : FD->parameters()) { if (!Param->getType()->isDependentType() && - !Context.hasSameType(Param->getType(), ExpectedParmType)) { + !Context.hasSameType(Param->getType(), ExpectedParmType1) && + !Context.hasSameType(Param->getType(), ExpectedParmType2)) { // Don't diagnose an implicit 'operator=='; we will have diagnosed the // corresponding defaulted 'operator<=>' already. if (!FD->isImplicit()) { Diag(FD->getLocation(), diag::err_defaulted_comparison_param) - << (int)DCK << Param->getType() << ExpectedParmType - << Param->getSourceRange(); + << (int)DCK << Param->getType() << ExpectedParmType1 + << !isa<CXXMethodDecl>(FD) + << ExpectedParmType2 << Param->getSourceRange(); } return true; } } + if (FD->getNumParams() == 2 && + !Context.hasSameType(FD->getParamDecl(0)->getType(), + FD->getParamDecl(1)->getType())) { + if (!FD->isImplicit()) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch) + << (int)DCK + << FD->getParamDecl(0)->getType() + << FD->getParamDecl(0)->getSourceRange() + << FD->getParamDecl(1)->getType() + << FD->getParamDecl(1)->getSourceRange(); + } + return true; + } // ... non-static const member ... if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { 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 a73b34870769..1a0ccc91741b 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 @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++2a -verify %s struct B {}; -bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}} +bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}} expected-note {{candidate}} bool operator<=>(const B&, const B&) = default; // expected-error {{three-way comparison operator can only be defaulted in a class definition}} template<typename T = void> @@ -9,18 +9,19 @@ template<typename T = void> struct A { friend bool operator==(const A&, const A&) = default; - friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}} + friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison operator; found 'const B &', expected 'A' or 'const A &'}} friend bool operator!=(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}} friend bool operator<(const A&, const A&); friend bool operator<(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted relational comparison}} - friend bool operator>(A, A) = default; // expected-error {{invalid parameter type for defaulted relational comparison}} + friend bool operator>(A, A) = default; // expected-warning {{implicitly deleted}} bool operator<(const A&) const; bool operator<=(const A&) const = default; bool operator==(const A&) const volatile && = default; // surprisingly, OK bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}} - bool operator>=(const B&) const = default; // expected-error {{invalid parameter type for defaulted relational comparison}} + bool operator>=(const B&) const = default; // expected-error-re {{invalid parameter type for defaulted relational comparison operator; found 'const B &', expected 'const A &'{{$}}}} static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}} + friend bool operator>(A, const A&) = default; // expected-error {{must have the same type}} expected-note {{would be the best match}} template<typename T = void> friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}} @@ -120,3 +121,14 @@ namespace LookupContext { } } } + +namespace P1946 { + struct A { + friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}} + }; + struct B { + A a; // expected-note {{no viable comparison}} + friend bool operator==(B, B) = default; // ok + friend bool operator==(const B&, const B&) = default; // expected-warning {{deleted}} + }; +} diff --git a/clang/test/CXX/class/class.compare/class.eq/p3.cpp b/clang/test/CXX/class/class.compare/class.eq/p3.cpp index a7356b5381cd..04db022fe730 100644 --- a/clang/test/CXX/class/class.compare/class.eq/p3.cpp +++ b/clang/test/CXX/class/class.compare/class.eq/p3.cpp @@ -11,3 +11,15 @@ static_assert(A{1, 2, 3, 4, 5} == A{1, 0, 3, 4, 5}); // expected-error {{failed} static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 0, 4, 5}); // expected-error {{failed}} static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 3, 0, 5}); // expected-error {{failed}} static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 3, 4, 0}); // expected-error {{failed}} + +struct B { + int a, b[3], c; + friend bool operator==(B, B) = default; +}; + +static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 4, 5}); +static_assert(B{1, 2, 3, 4, 5} == B{0, 2, 3, 4, 5}); // expected-error {{failed}} +static_assert(B{1, 2, 3, 4, 5} == B{1, 0, 3, 4, 5}); // expected-error {{failed}} +static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 0, 4, 5}); // expected-error {{failed}} +static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 0, 5}); // expected-error {{failed}} +static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 4, 0}); // expected-error {{failed}} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index f8dbc840763c..2d5a7a32f4a3 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -938,7 +938,7 @@ <h2 id="cxx20">C++2a implementation status</h2> </tr> <tr> <!-- from Kona 2019 --> <td><a href="https://wg21.link/p1185r2">P1185R2</a></td> - <td rowspan="3" class="svn" align="center">SVN</td> + <td rowspan="4" class="svn" align="center">SVN</td> </tr> <tr> <!-- from Cologne --> <td><a href="https://wg21.link/p1186r3">P1186R3</a></td> @@ -948,7 +948,6 @@ <h2 id="cxx20">C++2a implementation status</h2> </tr> <tr> <!-- from Belfast --> <td><a href="https://wg21.link/p1946r0">P1946R0</a></td> - <td rowspan="2" class="none" align="center">No</td> </tr> <tr> <td><a href="https://wg21.link/p1959r0">P1959R0</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits