llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: puneeth_aditya_5656 (mugiwaraluffy56)

<details>
<summary>Changes</summary>

## Summary
- Modified `argTypeIsABIEquivalent()` in `SemaCast.cpp` to allow 
pointer-to-integer and integer-to-pointer conversions when both types have the 
same width
- Updated test cases to verify the fix and adjusted existing tests that would 
be affected by the change

## Background
The `-Wcast-function-type` warning was overly strict when casting between 
function pointer types where the return or parameter types differ between a 
pointer type and an integer type of the same width (e.g., `void*` and 
`uintptr_t`).

On platforms where these types have the same size (e.g., 64-bit systems), such 
conversions are ABI-safe and commonly used in low-level/system programming.

Fixes #<!-- -->178388

## Test plan
- Added new test cases in `warn-cast-function-type.c` to verify pointer-integer 
same-width conversions don't warn
- Updated existing test cases that relied on `long` vs `void*` to use `short` 
vs `void*` to ensure warnings still fire for different-sized types

---
Full diff: https://github.com/llvm/llvm-project/pull/178390.diff


5 Files Affected:

- (modified) clang/lib/Sema/SemaCast.cpp (+11) 
- (modified) clang/test/Sema/warn-cast-function-type-strict.c (+2-1) 
- (modified) clang/test/Sema/warn-cast-function-type.c (+37-1) 
- (modified) clang/test/SemaCXX/warn-cast-function-type-strict.cpp (+3-2) 
- (modified) clang/test/SemaCXX/warn-cast-function-type.cpp (+3-2) 


``````````diff
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 5360f8a2908bf..670b2e1706d1e 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1145,6 +1145,17 @@ static bool argTypeIsABIEquivalent(QualType SrcType, 
QualType DestType,
         Context.getTypeSizeInChars(DestType))
       return true;
 
+  // Allow pointer-to-integral and integral-to-pointer conversions if sizes
+  // match. On platforms where pointers and certain integer types (like
+  // uintptr_t) have the same size, such conversions are ABI-safe.
+  if ((SrcType->isPointerType() &&
+       (DestType->isIntegralType(Context) || DestType->isEnumeralType())) ||
+      ((SrcType->isIntegralType(Context) || SrcType->isEnumeralType()) &&
+       DestType->isPointerType()))
+    if (Context.getTypeSizeInChars(SrcType) ==
+        Context.getTypeSizeInChars(DestType))
+      return true;
+
   return Context.hasSameUnqualifiedType(SrcType, DestType);
 }
 
diff --git a/clang/test/Sema/warn-cast-function-type-strict.c 
b/clang/test/Sema/warn-cast-function-type-strict.c
index c43e0f2fcbc63..5b9e9ca8f7666 100644
--- a/clang/test/Sema/warn-cast-function-type-strict.c
+++ b/clang/test/Sema/warn-cast-function-type-strict.c
@@ -6,6 +6,7 @@ int t(int array[static 12]);
 int u(int i);
 const int v(int i);
 int x(long);
+int y(short);
 
 typedef int (f1)(long);
 typedef int (f2)(void*);
@@ -40,7 +41,7 @@ void foo(void) {
   a = (f1 *)x;
   a = (f1 *)efunc; // strict-warning {{cast from 'int (*)(enum E)' to 'f1 *' 
(aka 'int (*)(long)') converts to incompatible function type}}
   a = (f1 *)e2func; // strict-warning {{cast from 'int (*)(enum E2)' to 'f1 *' 
(aka 'int (*)(long)') converts to incompatible function type}}
-  b = (f2 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}} */
+  b = (f2 *)y; /* expected-warning {{cast from 'int (*)(short)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}} */
   c = (f3 *)x; /* strict-warning {{cast from 'int (*)(long)' to 'f3 *' (aka 
'int (*)()') converts to incompatible function type}} */
   d = (f4 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 
'void (*)()') converts to incompatible function type}} */
   e = (f5 *)x; /* strict-warning {{cast from 'int (*)(long)' to 'f5 *' (aka 
'void (*)(void)') converts to incompatible function type}} */
diff --git a/clang/test/Sema/warn-cast-function-type.c 
b/clang/test/Sema/warn-cast-function-type.c
index d474dbf48b897..d2d580d0e8705 100644
--- a/clang/test/Sema/warn-cast-function-type.c
+++ b/clang/test/Sema/warn-cast-function-type.c
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 %s -fsyntax-only -Wextra -Wno-cast-function-type-strict 
-verify
 
 int x(long);
+int y(short);
 
 typedef int (f1)(long);
 typedef int (f2)(void*);
@@ -30,10 +31,45 @@ void foo(void) {
   a = (f1 *)x;
   a = (f1 *)efunc; // enum is just type system sugar, still passed as a long.
   a = (f1 *)e2func; // enum is just type system sugar, still passed as a long.
-  b = (f2 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}} */
+  b = (f2 *)y; /* expected-warning {{cast from 'int (*)(short)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}} */
   c = (f3 *)x;
   d = (f4 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 
'void (*)()') converts to incompatible function type}} */
   e = (f5 *)x;
   f = (f6 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f6 *' (aka 
'int (*)(long, int)') converts to incompatible function type}} */
   g = (f7 *)x;
 }
+
+// Test pointer-integer conversions with same width (issue #178388)
+// __INTPTR_TYPE__ and __UINTPTR_TYPE__ are guaranteed to have the same size 
as pointers.
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
+void *returns_ptr(void);
+uintptr_t returns_uintptr(void);
+intptr_t returns_intptr(void);
+
+typedef void *(*fn_returning_ptr)(void);
+typedef uintptr_t (*fn_returning_uintptr)(void);
+typedef intptr_t (*fn_returning_intptr)(void);
+
+int takes_ptr(void *);
+int takes_uintptr(uintptr_t);
+int takes_intptr(intptr_t);
+
+typedef int (*fn_taking_ptr)(void *);
+typedef int (*fn_taking_uintptr)(uintptr_t);
+typedef int (*fn_taking_intptr)(intptr_t);
+
+void test_ptr_int_same_width(void) {
+  // Return type: pointer to same-width integer should not warn
+  fn_returning_uintptr p1 = (fn_returning_uintptr)returns_ptr;    // no warning
+  fn_returning_intptr p2 = (fn_returning_intptr)returns_ptr;      // no warning
+  fn_returning_ptr p3 = (fn_returning_ptr)returns_uintptr;        // no warning
+  fn_returning_ptr p4 = (fn_returning_ptr)returns_intptr;         // no warning
+
+  // Parameter type: pointer to same-width integer should not warn
+  fn_taking_uintptr p5 = (fn_taking_uintptr)takes_ptr;            // no warning
+  fn_taking_intptr p6 = (fn_taking_intptr)takes_ptr;              // no warning
+  fn_taking_ptr p7 = (fn_taking_ptr)takes_uintptr;                // no warning
+  fn_taking_ptr p8 = (fn_taking_ptr)takes_intptr;                 // no warning
+}
diff --git a/clang/test/SemaCXX/warn-cast-function-type-strict.cpp 
b/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
index 9203c1aae8c90..79c3f64f13b5e 100644
--- a/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
+++ b/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
@@ -3,6 +3,7 @@
 // RUN: %clang_cc1 %s -fblocks -fsyntax-only -Wextra -verify
 
 int x(long);
+int z(short);
 
 typedef int (f1)(long);
 typedef int (f2)(void*);
@@ -40,8 +41,8 @@ void foo() {
   a = (f1 *)x;
   a = (f1 *)efunc; // strict-warning {{cast from 'int (*)(E)' to 'f1 *' (aka 
'int (*)(long)') converts to incompatible function type}}
   a = (f1 *)e2func; // strict-warning {{cast from 'int (*)(E2)' to 'f1 *' (aka 
'int (*)(long)') converts to incompatible function type}}
-  b = (f2 *)x; // expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}}
-  b = reinterpret_cast<f2 *>(x); // expected-warning {{cast from 'int 
(*)(long)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function 
type}}
+  b = (f2 *)z; // expected-warning {{cast from 'int (*)(short)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}}
+  b = reinterpret_cast<f2 *>(z); // expected-warning {{cast from 'int 
(*)(short)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function 
type}}
   c = (f3 *)x; // strict-warning {{cast from 'int (*)(long)' to 'f3 *' (aka 
'int (*)(...)') converts to incompatible function type}}
   d = (f4 *)x; // expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 
'void (*)(...)') converts to incompatible function type}}
   e = (f5 *)x; // strict-warning {{cast from 'int (*)(long)' to 'f5 *' (aka 
'void (*)()') converts to incompatible function type}}
diff --git a/clang/test/SemaCXX/warn-cast-function-type.cpp 
b/clang/test/SemaCXX/warn-cast-function-type.cpp
index 5f450f25f3f68..e61e63421e817 100644
--- a/clang/test/SemaCXX/warn-cast-function-type.cpp
+++ b/clang/test/SemaCXX/warn-cast-function-type.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 %s -fblocks -fsyntax-only -Wextra 
-Wno-cast-function-type-strict -verify
 
 int x(long);
+int y(short);
 
 typedef int (f1)(long);
 typedef int (f2)(void*);
@@ -39,8 +40,8 @@ void foo() {
   a = (f1 *)x;
   a = (f1 *)efunc; // enum is just type system sugar, still passed as a long.
   a = (f1 *)e2func; // enum is just type system sugar, still passed as a long.
-  b = (f2 *)x; // expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}}
-  b = reinterpret_cast<f2 *>(x); // expected-warning {{cast from 'int 
(*)(long)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function 
type}}
+  b = (f2 *)y; // expected-warning {{cast from 'int (*)(short)' to 'f2 *' (aka 
'int (*)(void *)') converts to incompatible function type}}
+  b = reinterpret_cast<f2 *>(y); // expected-warning {{cast from 'int 
(*)(short)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function 
type}}
   c = (f3 *)x;
   d = (f4 *)x; // expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 
'void (*)(...)') converts to incompatible function type}}
   e = (f5 *)x;

``````````

</details>


https://github.com/llvm/llvm-project/pull/178390
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to