https://github.com/mugiwaraluffy56 created https://github.com/llvm/llvm-project/pull/178390
## 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 >From a6abfafe33ef71dc2293037462d72208c910efcb Mon Sep 17 00:00:00 2001 From: mugiwaraluffy56 <[email protected]> Date: Wed, 28 Jan 2026 15:36:58 +0530 Subject: [PATCH] [Clang] Allow -Wcast-function-type for same-width pointer-integer conversions The -Wcast-function-type warning was too strict for function pointer casts involving conversions between pointer types and integer types that have the same width (e.g., void* and uintptr_t on platforms where they're the same size). This patch modifies argTypeIsABIEquivalent() to allow pointer-to-integral and integral-to-pointer conversions when both types have the same size, as such conversions are ABI-safe and commonly used in low-level/system code. Fixes #178388 Co-Authored-By: Claude Opus 4.5 <[email protected]> --- clang/lib/Sema/SemaCast.cpp | 11 ++++++ .../Sema/warn-cast-function-type-strict.c | 3 +- clang/test/Sema/warn-cast-function-type.c | 38 ++++++++++++++++++- .../warn-cast-function-type-strict.cpp | 5 ++- .../test/SemaCXX/warn-cast-function-type.cpp | 5 ++- 5 files changed, 56 insertions(+), 6 deletions(-) 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; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
