[clang] [clang-tools-extra] [clang] Handle _Atomic types in hasUniqueObjectRepresentations (PR #212768)
Aditya Medhane via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 29 06:28:58 PDT 2026
https://github.com/flash1729 created https://github.com/llvm/llvm-project/pull/212768
`__has_unique_object_representations(_Atomic(int))` returns false even though `_Atomic(int)` has the same object representation as `int`. Atomic types were never handled: they fail the trivial-copyability check up front (they aren't scalar types), and `_Atomic T` has been on the FIXME list at the end of the function since the original implementation. This is also the root cause of the false positive pinned in the `bugprone-suspicious-memory-comparison` tests since [D89651](https://reviews.llvm.org/D89651).
Handle `AtomicType` explicitly: `_Atomic(T)` has unique object representations iff `T` does and the atomic's size wasn't rounded up to a power of two (see `getTypeInfo`), since the rounding bytes are padding. The branch goes before the trivial-copyability check, which atomics always fail; triviality is judged on the value type instead.
Adds trait asserts to `type-traits.cpp` and flips the tidy FIXME test to expect no diagnostic. This is groundwork for a follow-up PR adding a Sema warning for `memcmp` on types without unique object representations, so the known false positive needed fixing first.
>From 8cebfe1aa29d466308528cccd539c38080a5029f Mon Sep 17 00:00:00 2001
From: flash1729 <sherlockedaditya at gmail.com>
Date: Wed, 29 Jul 2026 17:20:06 +0530
Subject: [PATCH] [clang] Handle _Atomic types in
hasUniqueObjectRepresentations
Atomic types aren't scalar, so the predicate rejected them before layout
was checked and fell through to false. _Atomic(T) shares T's representation
when sizes match; padding from size rounding makes it non-unique.
Fixes the FIXME in bugprone-suspicious-memory-comparison (D89651).
---
.../checkers/bugprone/suspicious-memory-comparison.c | 4 +---
clang/docs/ReleaseNotes.md | 6 ++++++
clang/lib/AST/ASTContext.cpp | 9 ++++++++-
clang/test/SemaCXX/type-traits.cpp | 10 ++++++++++
4 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c
index d3ecffec9a781..1f8bd7bd9f1ad 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c
@@ -286,9 +286,7 @@ struct AtomicMember {
};
void Test_AtomicMember(void) {
- // FIXME: this is a false positive as the list of objects with unique object
- // representations is incomplete.
+ // _Atomic(int) has the same object representation as int: no warning.
struct AtomicMember a, b;
memcmp(&a, &b, sizeof(struct AtomicMember));
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct AtomicMember' which does not have a unique object representation; consider comparing the members of the object manually
}
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 80e770a40838a..20b37f466b84f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -327,6 +327,12 @@ features cannot lower the translation-unit ABI level;
- Fixed a crash when classifying a call to a builtin with dependent arguments,
such as when the call is used as an `auto` non-type template argument.
+- `__has_unique_object_representations` now returns `true` for `_Atomic` types
+ whose object representation is identical to that of their value type, such
+ as `_Atomic(int)`. Atomic types whose size is rounded up to a power of two
+ (adding padding bits) continue to report `false`. This also fixes a false
+ positive in the `bugprone-suspicious-memory-comparison` clang-tidy check.
+
#### Bug Fixes to Attribute Support
- The `counted_by`/`counted_by_or_null` diagnostic that rejects a pointer whose
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2228811546c0f..6aea6cfcf25ca 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3062,6 +3062,14 @@ bool ASTContext::hasUniqueObjectRepresentations(
"hasUniqueObjectRepresentations should not be called with an "
"incomplete type");
+ // _Atomic(T) shares T's object representation unless its size was rounded
+ // up to a power of two, in which case the extra bytes are padding. Atomic
+ // types are never trivially copyable, so (9.1) is judged on the value type.
+ if (const auto *AT = Ty->getAs<AtomicType>())
+ return getTypeSize(AT) == getTypeSize(AT->getValueType()) &&
+ hasUniqueObjectRepresentations(AT->getValueType(),
+ CheckIfTriviallyCopyable);
+
// (9.1) - T is trivially copyable...
if (CheckIfTriviallyCopyable && !Ty.isTriviallyCopyableType(*this))
return false;
@@ -3102,7 +3110,6 @@ bool ASTContext::hasUniqueObjectRepresentations(
// FIXME: More cases to handle here (list by rsmith):
// vectors (careful about, eg, vector of 3 foo)
// _Complex int and friends
- // _Atomic T
// Obj-C block pointers
// Obj-C object pointers
// and perhaps OpenCL's various builtin types (pipe, sampler_t, event_t,
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index ff74461308fb1..246da619fe046 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3504,6 +3504,16 @@ static_assert(__has_unique_object_representations(const int *), "as are pointers
static_assert(__has_unique_object_representations(volatile int *), "as are pointers");
static_assert(__has_unique_object_representations(const volatile int *), "as are pointers");
+static_assert(__has_unique_object_representations(_Atomic(int)), "layout-identical atomics are");
+static_assert(!__has_unique_object_representations(_Atomic(float)), "value type is not unique");
+struct AtomicReprThreeChars { char a, b, c; };
+static_assert(!__has_unique_object_representations(_Atomic(AtomicReprThreeChars)),
+ "atomic size rounded up to a power of two adds padding");
+struct AtomicReprMember { _Atomic(int) x; };
+static_assert(__has_unique_object_representations(AtomicReprMember), "atomic member, no padding");
+struct AtomicReprPadded { char c; _Atomic(int) x; };
+static_assert(!__has_unique_object_representations(AtomicReprPadded), "padding before atomic member");
+
class C {};
using FP = int (*)(int);
using PMF = int (C::*)(int);
More information about the cfe-commits
mailing list