Skip to content

Commit

Permalink
[Clang] Fix defaulted equality operator so that it does not attempt t…
Browse files Browse the repository at this point in the history
…o compare unnamed bit-fields

If we look at class.bit p2 it tells us that that unnamed bit-fields are not
members and class.compare.default p5 tells us that we should only compare
non-static data members of the class.

This fixes: llvm/llvm-project#61335 and llvm/llvm-project#61417

Differential Revision: https://reviews.llvm.org/D146329
  • Loading branch information
shafik authored and veselypeta committed Aug 21, 2024
2 parents 034beda + 6d0fab4 commit e69cd6c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 0 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ Bug Fixes in This Version
- Fix a failed assertion due to an invalid source location when trying to form
a coverage report for an unresolved constructor expression.
(`#62105 <https://github.com/llvm/llvm-project/issues/62105>`_)
- Fix defaulted equality operator so that it does not attempt to compare unnamed
bit-fields. This fixes:
(`#61355 <https://github.com/llvm/llvm-project/issues/61335>`_) and
(`#61417 <https://github.com/llvm/llvm-project/issues/61417>`_)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7758,6 +7758,10 @@ class DefaultedComparisonVisitor {

// followed by the non-static data members of C
for (FieldDecl *Field : Record->fields()) {
// C++23 [class.bit]p2:
// Unnamed bit-fields are not members ...
if (Field->isUnnamedBitfield())
continue;
// Recursively expand anonymous structs.
if (Field->isAnonymousStructOrUnion()) {
if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(),
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,26 @@ void f2() {
(void)(b == 0);
}
} // namespace p2085_2

namespace GH61417 {
struct A {
unsigned x : 1;
unsigned : 0;
unsigned y : 1;

constexpr A() : x(0), y(0) {}
bool operator==(const A& rhs) const noexcept = default;
};

void f1() {
constexpr A a, b;
constexpr bool c = (a == b); // no diagnostic, we should not be comparing the
// unnamed bit-field which is indeterminate
}

void f2() {
A a, b;
bool c = (a == b); // no diagnostic nor crash during codegen attempting to
// access info for unnamed bit-field
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux -emit-llvm -o - | FileCheck %s

// GH61417
// Check that we don't attempt to compare the unnamed bitfields
struct A {
unsigned x : 1;
unsigned : 1;

friend bool operator==(A, A);
};


struct B {
unsigned x : 1;
unsigned : 31;

friend bool operator==(B, B);
};

bool operator==(A, A) = default;
// CHECK: define{{.*}} @_Zeq1AS_
// CHECK: %[[LHS:.+]] = alloca %struct.A, align 4
// CHECK: %[[RHS:.+]] = alloca %struct.A, align 4
// CHECK: %[[LHS_LOAD:.+]] = load i8, ptr %[[LHS]], align 4
// CHECK: %[[LHS_CLEAR:.+]] = and i8 %[[LHS_LOAD]], 1
// CHECK: %[[LHS_CAST:.+]] = zext i8 %[[LHS_CLEAR]] to i32

// CHECK: %[[RHS_LOAD:.+]] = load i8, ptr %[[RHS]]
// CHECK: %[[RHS_CLEAR:.+]] = and i8 %[[RHS_LOAD]], 1
// CHECK: %[[RHS_CAST:.+]] = zext i8 %[[RHS_CLEAR]] to i32
// CHECK: %[[CMP:.*]] = icmp eq i32 %[[LHS_CAST]], %[[RHS_CAST]]
// CHECK: ret i1 %[[CMP]]

bool operator==(B, B) = default;
// CHECK: define{{.*}} @_Zeq1BS_
// CHECK: %[[LHS_B:.+]] = alloca %struct.B, align 4
// CHECK: %[[RHS_B:.+]] = alloca %struct.B, align 4
// CHECK: %[[LHS_LOAD_B:.+]] = load i32, ptr %[[LHS_B]], align 4
// CHECK: %[[LHS_CLEAR_B:.+]] = and i32 %[[LHS_LOAD_B]], 1

// CHECK: %[[RHS_LOAD_B:.+]] = load i32, ptr %[[RHS_B]]
// CHECK: %[[RHS_CLEAR_B:.+]] = and i32 %[[RHS_LOAD_B]], 1
// CHECK: %[[CMP_B:.*]] = icmp eq i32 %[[LHS_CLEAR_B]], %[[RHS_CLEAR_B]]
// CHECK: ret i1 %[[CMP_B]]

0 comments on commit e69cd6c

Please sign in to comment.