From 6d0fab467efbc7ce92bd890d9618259c4995ddcc Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Fri, 14 Apr 2023 14:56:36 -0700 Subject: [PATCH] [Clang] Fix defaulted equality operator so that it does not attempt to 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: https://github.com/llvm/llvm-project/issues/61335 and https://github.com/llvm/llvm-project/issues/61417 Differential Revision: https://reviews.llvm.org/D146329 --- clang/docs/ReleaseNotes.rst | 4 ++ clang/lib/Sema/SemaDeclCXX.cpp | 4 ++ .../class.compare/class.compare.default/p1.cpp | 23 +++++++++++ ...defaulted_equality_ignore_unnamed_bitfields.cpp | 44 ++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 clang/test/CodeGenCXX/defaulted_equality_ignore_unnamed_bitfields.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d854590..1f66a87 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 `_) +- Fix defaulted equality operator so that it does not attempt to compare unnamed + bit-fields. This fixes: + (`#61355 `_) and + (`#61417 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7fd1231..26476f7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7758,6 +7758,10 @@ protected: // 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(), diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp index f07b19f..eadb571 100644 --- a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp +++ b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp @@ -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 +} +} diff --git a/clang/test/CodeGenCXX/defaulted_equality_ignore_unnamed_bitfields.cpp b/clang/test/CodeGenCXX/defaulted_equality_ignore_unnamed_bitfields.cpp new file mode 100644 index 0000000..0eb1493 --- /dev/null +++ b/clang/test/CodeGenCXX/defaulted_equality_ignore_unnamed_bitfields.cpp @@ -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]] -- 2.7.4