https://github.com/arthur3336 updated 
https://github.com/llvm/llvm-project/pull/174286

>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

Reply via email to