summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard@metafoo.co.uk>2019-10-27 23:10:50 -0700
committerRichard Smith <richard@metafoo.co.uk>2019-10-27 23:26:44 -0700
commita4facd355dc36bc83d5c2402856f5a3741890c9a (patch)
treef7d21cbd8a381c36c739b166fa41bc32d8eced8c /clang/lib/Sema/SemaDeclCXX.cpp
parent1a9c01c7f6c7e88676440869bbbe9f43fa45b109 (diff)
downloadbcm5719-llvm-a4facd355dc36bc83d5c2402856f5a3741890c9a.tar.gz
bcm5719-llvm-a4facd355dc36bc83d5c2402856f5a3741890c9a.zip
[c++20] Enforce rule that a union-like class or class with reference
members cannot have defaulted comparisons.
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp39
1 files changed, 36 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ccf6c0a604b..6a718db6c55 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7096,8 +7096,40 @@ bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD,
// A defaulted comparison operator function for class C is defined as
// deleted if any non-static data member of C is of reference type or C is
// a union-like class.
- // FIXME: Applying this to cases other than == and <=> is unreasonable.
- // FIXME: Implement.
+ llvm::SmallVector<CXXRecordDecl*, 4> Classes(1, RD);
+ FieldDecl *ReferenceMember = nullptr;
+ bool UnionLike = RD->isUnion();
+ while (!Classes.empty()) {
+ if (Classes.back()->isUnion())
+ UnionLike = true;
+ for (FieldDecl *FD : Classes.pop_back_val()->fields()) {
+ if (FD->getType()->isReferenceType())
+ ReferenceMember = FD;
+ if (FD->isAnonymousStructOrUnion())
+ Classes.push_back(FD->getType()->getAsCXXRecordDecl());
+ }
+ }
+ // For non-memberwise comparisons, this rule is unjustified, so we permit
+ // those cases as an extension.
+ bool Memberwise = DCK == DefaultedComparisonKind::Equal ||
+ DCK == DefaultedComparisonKind::ThreeWay;
+ if (ReferenceMember) {
+ Diag(FD->getLocation(),
+ Memberwise ? diag::err_defaulted_comparison_reference_member
+ : diag::ext_defaulted_comparison_reference_member)
+ << FD << RD;
+ Diag(ReferenceMember->getLocation(), diag::note_reference_member)
+ << ReferenceMember;
+ } else if (UnionLike) {
+ // If the class actually has no variant members, this rule similarly
+ // is unjustified, so we permit those cases too.
+ Diag(FD->getLocation(),
+ !Memberwise ? diag::ext_defaulted_comparison_union
+ : !RD->hasVariantMembers()
+ ? diag::ext_defaulted_comparison_empty_union
+ : diag::err_defaulted_comparison_union)
+ << FD << RD->isUnion() << RD;
+ }
// C++2a [class.eq]p1, [class.rel]p1:
// A [defaulted comparison other than <=>] shall have a declared return
@@ -7122,7 +7154,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD,
// the requirements for a constexpr function.
// FIXME: Apply this rule to all defaulted comparisons. The only way this
// can fail is if the return type of a defaulted operator<=> is not a literal
- // type.
+ // type. We should additionally consider whether any of the operations
+ // performed by the comparison invokes a non-constexpr function.
return false;
}
OpenPOWER on IntegriCloud