https://github.com/arthur3336 created
https://github.com/llvm/llvm-project/pull/174286
Fixes #174269
## Problem
The `readability-make-member-function-const` check incorrectly suggests adding
`const`
to member functions that return non-const references from dereferencing
pointer members within unions. This is a false positive because union members
share memory, making such cases inherently non-const-safe.
## Reproducible Example
```cpp
struct S {
union { int* resource; };
int& get() { return *resource; } // False positive: suggests const
const int& get() const { return *resource; }
};
```
## Solution
This patch adds special handling for union members in the const-safety
analysis. When a member access involves a pointer or reference type within a
union, it's correctly identified as non-const usage.
## Changes
- Added union member detection in `MakeMemberFunctionConstCheck.cpp`
- Added comprehensive test cases for various union scenarios
## Testing
**Before this fix:**
```bash
$ clang-tidy -checks='-*,readability-make-member-function-const' test.cpp
test.cpp:3:10: warning: method 'get' can be made const
[readability-make-member-function-const]
```
**After this fix:**
```bash
$ clang-tidy -checks='-*,readability-make-member-function-const' test.cpp
# No warning for union case (correctly suppressed)
```
### How to Test
1. Create test file with the example above
2. Run: `clang-tidy -checks='-*,readability-make-member-function-const'
test.cpp`
3. Verify no false positive for union pointer members
4. Run: `ninja check-clang-tidy-readability-make-member-function-const`
### Test Coverage
- Union with pointer members returning non-const references
- Union with value types (should still get const suggestion where appropriate)
- Named vs anonymous unions
- Unions with multiple members
- Comparison with regular struct behavior (unchanged)
All new tests pass. No regressions in existing tests.
>From 90b5b76590304dd7f29be2e9f1c97ce366f88120 Mon Sep 17 00:00:00 2001
From: Arthur Courteaud <[email protected]>
Date: Sat, 3 Jan 2026 19:18:54 +0100
Subject: [PATCH] [clang-tidy] Fix false positive in
readability-make-member-function-const for unions with pointer/reference
members
Fixes #174269
The check incorrectly suggested adding const to member functions that
return non-const references from dereferencing pointer members within
unions. Union members share memory, making such cases inherently
non-const-safe.
Added special handling to detect pointer/reference members within unions
and correctly mark them as non-const usage.
---
.../MakeMemberFunctionConstCheck.cpp | 11 ++++
.../make-member-function-const.cpp | 56 +++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git
a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
index 2e6edd706b131..59b5c9770c936 100644
--- a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -154,6 +154,17 @@ class FindUsageOfThis : public
RecursiveASTVisitor<FindUsageOfThis> {
// 1) has builtin type (a 'const int' cannot be modified),
// 2) or it's a public member (the pointee of a public 'int * const' can
// can be modified by any user of the class).
+
+ // Union members are never safe for pointer/reference types
+ // (all union members share memory).
+ if (const auto *Field = dyn_cast<FieldDecl>(Member->getMemberDecl())) {
+ if (Field->getParent()->isUnion()) {
+ QualType MemberType = Field->getType();
+ if (MemberType->isPointerType() || MemberType->isReferenceType())
+ return false;
+ }
+ }
+
if (Member->getFoundDecl().getAccess() != AS_public &&
!Cast->getType()->isBuiltinType())
return false;
diff --git
a/clang-tools-extra/test/clang-tidy/checkers/readability/make-member-function-const.cpp
b/clang-tools-extra/test/clang-tidy/checkers/readability/make-member-function-const.cpp
index 72a8e362b9c8a..b62c75875a1ca 100644
---
a/clang-tools-extra/test/clang-tidy/checkers/readability/make-member-function-const.cpp
+++
b/clang-tools-extra/test/clang-tidy/checkers/readability/make-member-function-const.cpp
@@ -336,3 +336,59 @@ struct MemberFunctionPointer {
};
} // namespace Keep
+
+namespace UnionMemberAccess {
+ // Test case from GitHub issue #174269
+ // Union with pointer member returning non-const reference
+ struct UnionWithPointer {
+ union { int* resource; };
+ int& get() { return *resource; } // Should NOT trigger warning
+ const int& get() const { return *resource; }
+ };
+
+ // Union with pointer - single method variant
+ struct UnionWithPointerSingle {
+ union { int* resource; };
+ int& get() { return *resource; } // Should NOT trigger warning
+ };
+
+ // Union with value type - should still suggest const where appropriate
+ struct UnionWithValue {
+ union { int value; };
+ int get() { return value; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'get' can be made const
+ // CHECK-FIXES: int get() const {
+ };
+
+ // Union with multiple pointer members
+ struct UnionMultiplePointers {
+ union {
+ int* int_ptr;
+ double* double_ptr;
+ };
+ int& getInt() { return *int_ptr; } // Should NOT trigger warning
+ double& getDouble() { return *double_ptr; } // Should NOT trigger warning
+ };
+
+ // Named union member access
+ struct NamedUnion {
+ union Inner {
+ int* resource;
+ } inner;
+ int& get() { return *inner.resource; } // Should NOT trigger warning
+ };
+
+ // Union with reference member
+ struct UnionWithReference {
+ union { int& ref; };
+ int& get() { return ref; } // Should NOT trigger warning
+ };
+
+ // Regular struct for comparison - this SHOULD work as before
+ struct RegularStruct {
+ private:
+ int* ptr;
+ public:
+ int& get() { return *ptr; } // Should NOT trigger warning (private
non-const access)
+ };
+} // namespace UnionMemberAccess
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits