[clang] [clang][Sema] Don't issue -Wcast-function-type-mismatch for enums with a matching underlying type (PR #87793)
Raul Tambre via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 5 08:11:12 PDT 2024
https://github.com/tambry created https://github.com/llvm/llvm-project/pull/87793
Enums are passed as their underlying integral type so they're ABI compatible if the size matches.
Useful with C APIs that pass user-controlled values to callbacks that can be made type safe by using enumerations (e.g. GStreamer).
Discovered internally in some code after 999d4f840777bf8de26d45947192aa0728edc0fb.
>From 21a85320f485e4c11e734c24c6c1d74f8bea215d Mon Sep 17 00:00:00 2001
From: Raul Tambre <raul at tambre.ee>
Date: Fri, 5 Apr 2024 18:05:09 +0300
Subject: [PATCH] [clang][Sema] Don't issue -Wcast-function-type-mismatch for
enums with a matching underlying type
Enums are passed as their underlying integral type so they're ABI compatible if the size matches.
Useful with C APIs that pass user-controlled values to callbacks that can be made type safe by using enumerations (e.g. GStreamer).
---
clang/lib/Sema/SemaCast.cpp | 7 ++++---
clang/test/Sema/warn-cast-function-type-strict.c | 4 ++++
clang/test/Sema/warn-cast-function-type.c | 4 ++++
clang/test/SemaCXX/warn-cast-function-type-strict.cpp | 4 ++++
clang/test/SemaCXX/warn-cast-function-type.cpp | 4 ++++
5 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 9d85568d97b2d2..b93724a85999be 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1083,9 +1083,10 @@ static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType,
return true;
// Allow integral type mismatch if their size are equal.
- if (SrcType->isIntegralType(Context) && DestType->isIntegralType(Context))
- if (Context.getTypeInfoInChars(SrcType).Width ==
- Context.getTypeInfoInChars(DestType).Width)
+ if ((SrcType->isIntegralType(Context) || SrcType->isEnumeralType()) &&
+ (DestType->isIntegralType(Context) || DestType->isEnumeralType()))
+ 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 b0a70cf324b711..b21365cdd30a57 100644
--- a/clang/test/Sema/warn-cast-function-type-strict.c
+++ b/clang/test/Sema/warn-cast-function-type-strict.c
@@ -29,8 +29,12 @@ f8 *h;
f9 *i;
f10 *j;
+enum E : long;
+int efunc(enum E);
+
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}}
b = (f2 *)x; /* expected-warning {{cast from 'int (*)(long)' 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}} */
diff --git a/clang/test/Sema/warn-cast-function-type.c b/clang/test/Sema/warn-cast-function-type.c
index 09d169026b1c86..969a62043791f4 100644
--- a/clang/test/Sema/warn-cast-function-type.c
+++ b/clang/test/Sema/warn-cast-function-type.c
@@ -19,8 +19,12 @@ f5 *e;
f6 *f;
f7 *g;
+enum E : long;
+int efunc(enum E);
+
void foo(void) {
a = (f1 *)x;
+ a = (f1 *)efunc; // 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}} */
c = (f3 *)x;
d = (f4 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 'void (*)()') converts to incompatible function type}} */
diff --git a/clang/test/SemaCXX/warn-cast-function-type-strict.cpp b/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
index 8887b3c4c5d535..c49b0ac4b26a23 100644
--- a/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
+++ b/clang/test/SemaCXX/warn-cast-function-type-strict.cpp
@@ -29,8 +29,12 @@ struct S
typedef void (S::*mf)(int);
+enum E : long;
+int efunc(E);
+
void foo() {
a = (f1 *)x;
+ a = (f1 *)efunc; // strict-warning {{cast from 'int (*)(E)' 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}}
c = (f3 *)x; // strict-warning {{cast from 'int (*)(long)' to 'f3 *' (aka 'int (*)(...)') 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 db2ee030fcbfc9..467fcd6abc2482 100644
--- a/clang/test/SemaCXX/warn-cast-function-type.cpp
+++ b/clang/test/SemaCXX/warn-cast-function-type.cpp
@@ -28,8 +28,12 @@ struct S
typedef void (S::*mf)(int);
+enum E : long;
+int efunc(E);
+
void foo() {
a = (f1 *)x;
+ a = (f1 *)efunc; // 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}}
c = (f3 *)x;
More information about the cfe-commits
mailing list