massberg created this revision. massberg added a reviewer: ilya-biryukov. Herald added a project: All. massberg requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This patch implemed the change proposed in [P2002R1] to 11.11.1 [class.compare.default] paragraph 1. A defaulted compariosn operator function must be non-volatile and must either have no ref-qualifier or the ref-qualifier &. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D148924 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaDeclCXX.cpp clang/test/CXX/class/class.compare/class.compare.default/p1.cpp Index: clang/test/CXX/class/class.compare/class.compare.default/p1.cpp =================================================================== --- clang/test/CXX/class/class.compare/class.compare.default/p1.cpp +++ clang/test/CXX/class/class.compare/class.compare.default/p1.cpp @@ -15,7 +15,8 @@ bool operator<(const A&) const; bool operator<=(const A&) const = default; - bool operator==(const A&) const volatile && = default; // surprisingly, OK + bool operator==(const A&) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on defaulted comparison operators}} + bool operator>=(const A&) const volatile = default; // expected-error {{defaulted comparison operator function must not be volatile}} 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-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}} Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -8579,8 +8579,8 @@ // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // 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 non-static const non-volatile member of C having one parameter of type + // const C& and either no ref-qualifier or the ref-qualifier &, or // -- a friend of C having two parameters of type const C& or two // parameters of type C. @@ -8590,6 +8590,16 @@ auto *MD = cast<CXXMethodDecl>(FD); assert(!MD->isStatic() && "comparison function cannot be a static member"); + const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>(); + if (FnType->isVolatile()) { + Diag(FD->getLocation(), diag::err_volatile_comparison_operator); + return true; + } + if (FnType->getRefQualifier() == RQ_RValue) { + Diag(FD->getLocation(), diag::err_ref_qualifier_comparison_operator); + return true; + } + // If we're out-of-class, this is the class we're comparing. if (!RD) RD = MD->getParent(); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9430,6 +9430,10 @@ def note_in_declaration_of_implicit_equality_comparison : Note< "while declaring the corresponding implicit 'operator==' " "for this defaulted 'operator<=>'">; +def err_volatile_comparison_operator : Error< + "defaulted comparison operator function must not be volatile">; +def err_ref_qualifier_comparison_operator : Error< + "ref-qualifier '&&' is not allowed on defaulted comparison operators">; def ext_implicit_exception_spec_mismatch : ExtWarn< "function previously declared with an %select{explicit|implicit}0 exception "
Index: clang/test/CXX/class/class.compare/class.compare.default/p1.cpp =================================================================== --- clang/test/CXX/class/class.compare/class.compare.default/p1.cpp +++ clang/test/CXX/class/class.compare/class.compare.default/p1.cpp @@ -15,7 +15,8 @@ bool operator<(const A&) const; bool operator<=(const A&) const = default; - bool operator==(const A&) const volatile && = default; // surprisingly, OK + bool operator==(const A&) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on defaulted comparison operators}} + bool operator>=(const A&) const volatile = default; // expected-error {{defaulted comparison operator function must not be volatile}} 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-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}} Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -8579,8 +8579,8 @@ // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // 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 non-static const non-volatile member of C having one parameter of type + // const C& and either no ref-qualifier or the ref-qualifier &, or // -- a friend of C having two parameters of type const C& or two // parameters of type C. @@ -8590,6 +8590,16 @@ auto *MD = cast<CXXMethodDecl>(FD); assert(!MD->isStatic() && "comparison function cannot be a static member"); + const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>(); + if (FnType->isVolatile()) { + Diag(FD->getLocation(), diag::err_volatile_comparison_operator); + return true; + } + if (FnType->getRefQualifier() == RQ_RValue) { + Diag(FD->getLocation(), diag::err_ref_qualifier_comparison_operator); + return true; + } + // If we're out-of-class, this is the class we're comparing. if (!RD) RD = MD->getParent(); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9430,6 +9430,10 @@ def note_in_declaration_of_implicit_equality_comparison : Note< "while declaring the corresponding implicit 'operator==' " "for this defaulted 'operator<=>'">; +def err_volatile_comparison_operator : Error< + "defaulted comparison operator function must not be volatile">; +def err_ref_qualifier_comparison_operator : Error< + "ref-qualifier '&&' is not allowed on defaulted comparison operators">; def ext_implicit_exception_spec_mismatch : ExtWarn< "function previously declared with an %select{explicit|implicit}0 exception "
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits