[clang] f1ac334 - [Clang][SemaCXX] Preserve qualifiers in derived-to-base cast in defaulted comparison operators (#102619)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 5 00:41:43 PDT 2024


Author: Mital Ashok
Date: 2024-09-05T09:41:39+02:00
New Revision: f1ac334b13c22222ed5c71bad04ed8345b2be135

URL: https://github.com/llvm/llvm-project/commit/f1ac334b13c22222ed5c71bad04ed8345b2be135
DIFF: https://github.com/llvm/llvm-project/commit/f1ac334b13c22222ed5c71bad04ed8345b2be135.diff

LOG: [Clang][SemaCXX] Preserve qualifiers in derived-to-base cast in defaulted comparison operators (#102619)

Fixes #102588

Co-authored-by: cor3ntin <corentinjabot at gmail.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/SemaCXX/cxx20-default-compare.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1520f7a2916aae..44ffad94ef41fc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -355,6 +355,8 @@ Bug Fixes to C++ Support
 - Fix an issue with dependent source location expressions (#GH106428), (#GH81155), (#GH80210), (#GH85373)
 - Fixed a bug in the substitution of empty pack indexing types. (#GH105903)
 - Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
+- 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 3044f1218f5b23..f90f16c2923d03 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8450,10 +8450,12 @@ 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