Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
50 changes: 50 additions & 0 deletions clang/test/SemaCXX/cxx20-default-compare.cpp
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
};
}
Loading