[clang] [Clang][SemaCXX] Preserve qualifiers in derived-to-base cast in defaulted comparison operators (PR #102619)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 9 07:05:15 PDT 2024
https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/102619
Fixes #102588
>From f47340974464dccae08980a1f8e78f0982169a58 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Fri, 9 Aug 2024 15:03:38 +0100
Subject: [PATCH] [Clang][SemaCXX] Preserve qualifiers in derived-to-base cast
in defaulted comparison operators
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/Sema/SemaDeclCXX.cpp | 9 ++--
clang/test/SemaCXX/cxx20-default-compare.cpp | 50 ++++++++++++++++++++
3 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7a05ccf3184111..30bc36bd0d6cd7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -216,6 +216,7 @@ Bug Fixes to C++ Support
- Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667),
(#GH99877).
- Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions.
+- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b07e555afcaccf..a478bdb46faa05 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8414,10 +8414,11 @@ class DefaultedComparisonSynthesizer
if (Obj.first.isInvalid() || Obj.second.isInvalid())
return {ExprError(), ExprError()};
CXXCastPath Path = {Base};
- return {S.ImpCastExprToType(Obj.first.get(), Base->getType(),
- CK_DerivedToBase, VK_LValue, &Path),
- S.ImpCastExprToType(Obj.second.get(), Base->getType(),
- CK_DerivedToBase, VK_LValue, &Path)};
+ const auto CastToBase = [&](Expr *E) {
+ QualType ToType = S.Context.getQualifiedType(Base->getType(), E->getType().getQualifiers());
+ return S.ImpCastExprToType(E, ToType, CK_DerivedToBase, VK_LValue, &Path);
+ };
+ return {CastToBase(Obj.first.get()), CastToBase(Obj.second.get())};
}
ExprPair getField(FieldDecl *Field) {
diff --git a/clang/test/SemaCXX/cxx20-default-compare.cpp b/clang/test/SemaCXX/cxx20-default-compare.cpp
index 7074ee885ac4a2..3e4673c31e4890 100644
--- a/clang/test/SemaCXX/cxx20-default-compare.cpp
+++ b/clang/test/SemaCXX/cxx20-default-compare.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -std=c++23 -verify -Wfloat-equal
+#include "Inputs/std-compare.h"
+
struct Foo {
float val;
bool operator==(const Foo &) const;
@@ -15,3 +17,51 @@ bool operator==(const Foo &, const Foo &) = default; // expected-warning {{comp
// Declare the defaulted comparison function as a non-member function. Arguments are passed by value.
bool operator==(Foo, Foo) = default; // expected-warning {{comparing floating point with == or != is unsafe}} expected-note {{in defaulted equality comparison operator for 'Foo' first required here}}
+
+namespace GH102588 {
+struct A {
+ int i = 0;
+ constexpr operator int() const { return i; }
+ constexpr operator int&() { return ++i; }
+};
+
+struct B : A {
+ bool operator==(const B &) const = default;
+};
+
+constexpr bool f() {
+ B x;
+ return x == x;
+}
+
+static_assert(f());
+
+struct ConstOnly {
+ std::strong_ordering operator<=>(const ConstOnly&) const;
+ std::strong_ordering operator<=>(ConstOnly&) = delete;
+ friend bool operator==(const ConstOnly&, const ConstOnly&);
+ friend bool operator==(ConstOnly&, ConstOnly&) = delete;
+};
+
+struct MutOnly {
+ std::strong_ordering operator<=>(const MutOnly&) const = delete;;
+ std::strong_ordering operator<=>(MutOnly&);
+ friend bool operator==(const MutOnly&, const MutOnly&) = delete;;
+ friend bool operator==(MutOnly&, MutOnly&);
+};
+
+struct ConstCheck : ConstOnly {
+ friend std::strong_ordering operator<=>(const ConstCheck&, const ConstCheck&) = default;
+ std::strong_ordering operator<=>(ConstCheck const& __restrict) const __restrict = default;
+ friend bool operator==(const ConstCheck&, const ConstCheck&) = default;
+ bool operator==(this const ConstCheck&, const ConstCheck&) = default;
+};
+
+// FIXME: Non-reference explicit object parameter are rejected
+struct MutCheck : MutOnly {
+ friend bool operator==(MutCheck, MutCheck) = default;
+ // std::strong_ordering operator<=>(this MutCheck, MutCheck) = default;
+ friend std::strong_ordering operator<=>(MutCheck, MutCheck) = default;
+ // bool operator==(this MutCheck, MutCheck) = default;
+};
+}
More information about the cfe-commits
mailing list