[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-commits
Subject: [PATCH] D103929: [clang] P2085R0: Consistent defaulted comparisons
From: Richard Smith - zygoloid via Phabricator via cfe-commits <cfe-commits () lists ! llvm
Date: 2021-06-30 21:04:52
Message-ID: s5NOSDzhTbqqzSuCBc1JYQ () geopod-ismtpd-2-1
[Download RAW message or body]
rsmith added a comment.
Thanks!
I think you may be missing an implementation of this rule:
> A definition of a comparison operator as defaulted that appears in a class shall be \
> the first declaration of that function.
In particular, this is now invalid:
struct A;
bool operator==(A, A);
struct A {
friend bool operator==(A, A) = default; // error, not first declaration
};
As a subtle detail, I'm also not sure whether we handle the following rule properly, \
and I'd like to see some tests:
> A comparison operator function for class C that is defaulted on its first \
> declaration and is not defined as deleted is implicitly defined when it is odr-used \
> or needed for constant evaluation.
In particular, a comparison function that's defaulted on its first declaration is \
defined when it's used, but if it's defaulted on a second or subsequent declaration \
then it's immediately defined:
template<char C> struct Broken {
template<typename T = void> bool operator==(Broken, Broken) { return T::result; }
};
struct A { Broken<'A'> b; };
bool operator==(A, A) = default; // ok, does not try to define the function until \
it's used
struct B { Broken<'B'> b; };
bool operator==(B, B);
bool operator==(B, B) = default; // error, immediately defined, resulting in \
instantiation of Broken<'B'>::operator==, resulting in a hard error
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:8368-8373
+ CXXRecordDecl *RD =
+ dyn_cast<CXXRecordDecl>(FD->getCanonicalDecl()->getLexicalDeclContext());
- CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
- assert(RD && "defaulted comparison is not defaulted in a class");
+ if (!RD) {
+ RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
+ }
----------------
I don't think you can do the "member or friend" check this way. P2085R0 doesn't \
require either the defaulted declaration or the first declaration to be within the \
class, and it doesn't matter which class contains the first declaration, if any. For \
example, this is valid:
```
struct A;
class B {
friend bool operator==(A, A); // first declaration not in class A
bool operator==(B);
};
class A {
friend bool operator==(A, A);
B b;
};
// ok, can access both A::b and B::operator==.
bool operator==(A, A) = default; // defaulted declaration not in class A
```
I think there are two reasonable options here:
1) First work out the class type for which we're defaulting a comparison and then \
traverse the list of redeclarations of the function looking for one that's lexically \
within the class, or 2) First work out the class type for which we're defaulting a \
comparison and then check that the function is either a member of that class or is in \
the list of that class's friends. Either approach seems fine to me.
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:8614-8615
+
+ CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(FD->getCanonicalDecl()->getLexicalDeclContext());
SourceLocation BodyLoc =
----------------
This is not necessarily the right class. The first declaration might not lexically be \
in a class at all, in a case like: ```
struct A;
bool operator==(A, A);
struct A {
friend bool operator==(A, A);
};
bool operator==(A, A) = default;
```
================
Comment at: clang/lib/Sema/SemaTemplateInstantiate.cpp:765
+ diag::note_comparison_synthesized_at)
+ << (int)DFK.asComparison() << FD;
+ }
----------------
Passing in a function declaration here doesn't seem appropriate; this will diagnose \
"in defaulted equality comparison operator for 'operator==' first required here", \
when we wanted to say "in defaulted equality comparison operator for 'T' first \
required here". You'll presumably need some mechanism to determine the type being \
compared (something like \
`FD->getParamDecl(0)->getType().getNonReferenceType().getUnqualifiedType()`, though \
maybe you can share some code with `CheckExplicitlyDefaultedComparison`).
================
Comment at: clang/test/CXX/class/class.compare/class.compare.default/p6.cpp:1
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
----------------
The file names here indicate the paragraph within the standard that's being tested; \
p6 would be tests for paragraph 6 of [class.compare.default]. This test doesn't \
appear to have anything to do with [class.compare.default] paragraph 6; it appears to \
be testing paragraph 1. Please can you move these tests to p1.cpp as appropriate?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D103929/new/
https://reviews.llvm.org/D103929
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic