forked from OSchip/llvm-project
Default implicit function pointer conversions diagnostic to be an error
Implicitly converting between incompatible function pointers in C is currently a default-on warning (it is an error in C++). However, this is very poor security posture. A mismatch in parameters or return types, or a mismatch in calling conventions, etc can lead to exploitable security vulnerabilities. Rather than allow this unsafe practice with a warning, this patch strengthens the warning to be an error (while still allowing users the ability to disable the error or the warning entirely to ease migration). Users should either ensure the signatures are correctly compatible or they should use an explicit cast if they believe that's more reasonable. Differential Revision: https://reviews.llvm.org/D131351
This commit is contained in:
parent
bc9617899c
commit
af01f717c4
|
@ -13,7 +13,9 @@ void handler_bad1(int) {
|
|||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: standard function '_exit' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
}
|
||||
|
||||
void handler_bad2(void *dst, const void *src) {
|
||||
void handler_bad2(int) {
|
||||
void *dst;
|
||||
const void *src;
|
||||
memcpy(dst, src, 10);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: standard function 'memcpy' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ typedef void (*sighandler_t)(int);
|
|||
sighandler_t signal(int signum, sighandler_t handler);
|
||||
|
||||
void f_extern(void);
|
||||
void f_extern_handler(int);
|
||||
|
||||
void handler_printf(int) {
|
||||
printf("1234");
|
||||
|
@ -185,8 +186,8 @@ void test_other(void) {
|
|||
signal(SIGINT, _Exit);
|
||||
signal(SIGINT, other_call);
|
||||
// CHECK-NOTES: :[[@LINE-1]]:18: warning: standard function 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
|
||||
signal(SIGINT, f_extern);
|
||||
// CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
|
||||
signal(SIGINT, f_extern_handler);
|
||||
// CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern_handler' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
|
||||
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
|
|
@ -85,6 +85,10 @@ Improvements to Clang's diagnostics
|
|||
- ``-Wbitfield-constant-conversion`` now diagnoses implicit truncation when 1 is
|
||||
assigned to a 1-bit signed integer bitfield. This fixes
|
||||
`Issue 53253 <https://github.com/llvm/llvm-project/issues/53253>`_.
|
||||
- ``-Wincompatible-function-pointer-types`` now defaults to an error in all C
|
||||
language modes. It may be downgraded to a warning with
|
||||
``-Wno-error=incompatible-function-pointer-types`` or disabled entirely with
|
||||
``-Wno-implicit-function-pointer-types``.
|
||||
|
||||
Non-comprehensive list of changes in this release
|
||||
-------------------------------------------------
|
||||
|
|
|
@ -8157,24 +8157,6 @@ def err_typecheck_convert_incompatible_pointer : Error<
|
|||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">;
|
||||
def ext_typecheck_convert_incompatible_function_pointer : ExtWarn<
|
||||
"incompatible function pointer types "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
"|%diff{passing $ to parameter of type $|"
|
||||
"passing to parameter of different type}0,1"
|
||||
"|%diff{returning $ from a function with result type $|"
|
||||
"returning from function with different return type}0,1"
|
||||
"|%diff{converting $ to type $|converting between types}0,1"
|
||||
"|%diff{initializing $ with an expression of type $|"
|
||||
"initializing with expression of different type}0,1"
|
||||
"|%diff{sending $ to parameter of type $|"
|
||||
"sending to parameter of different type}0,1"
|
||||
"|%diff{casting $ to type $|casting between types}0,1}2"
|
||||
"%select{|; dereference with *|"
|
||||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">,
|
||||
InGroup<IncompatibleFunctionPointerTypes>;
|
||||
def err_typecheck_convert_incompatible_function_pointer : Error<
|
||||
"incompatible function pointer types "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
|
@ -8192,6 +8174,9 @@ def err_typecheck_convert_incompatible_function_pointer : Error<
|
|||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">;
|
||||
def ext_typecheck_convert_incompatible_function_pointer : ExtWarn<
|
||||
err_typecheck_convert_incompatible_function_pointer.Text>,
|
||||
InGroup<IncompatibleFunctionPointerTypes>, DefaultError;
|
||||
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
"|%diff{passing $ to parameter of type $|"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -Wno-strict-prototypes -fcf-protection=branch -triple i386-linux-gnu %s -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -Wno-strict-prototypes -Wno-incompatible-function-pointer-types -fcf-protection=branch -triple i386-linux-gnu %s -o - | FileCheck %s
|
||||
|
||||
// CHECK: @t5 = weak{{.*}} global i32 2
|
||||
int t5 __attribute__((weak)) = 2;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -no-opaque-pointers -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -no-opaque-pointers -triple %itanium_abi_triple -Wno-incompatible-function-pointer-types -emit-llvm %s -o - | FileCheck %s
|
||||
// CHECK: _Z1fPA10_1X
|
||||
// CHECK: _Z1fPFvvE
|
||||
|
||||
|
|
|
@ -15,5 +15,5 @@ void __attribute__((aarch64_sve_pcs)) foo3(void) {} // expected-error {{function
|
|||
typedef int (*fn_ty)(void);
|
||||
typedef int __attribute__((aarch64_sve_pcs)) (*aasvepcs_fn_ty)(void);
|
||||
void foo4(fn_ty ptr1, aasvepcs_fn_ty ptr2) {
|
||||
ptr1 = ptr2; // expected-warning {{incompatible function pointer types}}
|
||||
ptr1 = ptr2; // expected-error {{incompatible function pointer types}}
|
||||
}
|
||||
|
|
|
@ -15,5 +15,5 @@ void __attribute__((aarch64_vector_pcs)) foo3(void) {} // expected-error {{funct
|
|||
typedef int (*fn_ty)(void);
|
||||
typedef int __attribute__((aarch64_vector_pcs)) (*aavpcs_fn_ty)(void);
|
||||
void foo4(fn_ty ptr1, aavpcs_fn_ty ptr2) {
|
||||
ptr1 = ptr2; // expected-warning {{incompatible function pointer types}}
|
||||
ptr1 = ptr2; // expected-error {{incompatible function pointer types}}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ typedef void (*callback_2t)(void);
|
|||
void foo(callback_ns_1t nsfptr, // expected-error{{functions may not be declared with 'cmse_nonsecure_call' attribute}}
|
||||
callback_1t fptr) __attribute__((cmse_nonsecure_call))
|
||||
{
|
||||
callback_1t fp1 = nsfptr; // expected-warning{{incompatible function pointer types initializing 'callback_1t'}}
|
||||
callback_ns_1t fp2 = fptr; // expected-warning{{incompatible function pointer types initializing 'callback_ns_1t'}}
|
||||
callback_1t fp1 = nsfptr; // expected-error{{incompatible function pointer types initializing 'callback_1t'}}
|
||||
callback_ns_1t fp2 = fptr; // expected-error{{incompatible function pointer types initializing 'callback_ns_1t'}}
|
||||
callback_2t fp3 = fptr;
|
||||
callback_ns_2t fp4 = nsfptr;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ void testNoCfCheckImpl(double __attribute__((nocf_check)) i) {} // expected-warn
|
|||
// Allow attributed function pointers as well as casting between attributed
|
||||
// and non-attributed function pointers.
|
||||
void testNoCfCheckMismatch(FuncPointer f) {
|
||||
FuncPointerWithNoCfCheck fNoCfCheck = f; // expected-warning {{incompatible function pointer types}}
|
||||
FuncPointerWithNoCfCheck fNoCfCheck = f; // expected-error {{incompatible function pointer types}}
|
||||
(*fNoCfCheck)(); // no-warning
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ static int funk(char *s) {
|
|||
void next(void);
|
||||
void foo4(void) {
|
||||
int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(const char *)' with an expression of type 'int (^)(char *)'}}
|
||||
int (*yy)(const char *s) = funk; // expected-warning {{incompatible function pointer types initializing 'int (*)(const char *)' with an expression of type 'int (char *)'}}
|
||||
int (*yy)(const char *s) = funk; // expected-error {{incompatible function pointer types initializing 'int (*)(const char *)' with an expression of type 'int (char *)'}}
|
||||
|
||||
int (^nested)(char *s) = ^(char *str) { void (^nest)(void) = ^(void) { printf("%s\n", str); }; next(); return 1; };
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ void call(void) {
|
|||
fp call_me = func;
|
||||
call_me(1, 2, 3); // c2x-error {{too many arguments to function call, expected 0, have 3}}
|
||||
|
||||
fp nope = other_func; // c2x-warning {{incompatible function pointer types initializing 'fp' (aka 'void (*)(void)') with an expression of type 'void (int)'}}
|
||||
fp nope = other_func; // c2x-error {{incompatible function pointer types initializing 'fp' (aka 'void (*)(void)') with an expression of type 'void (int)'}}
|
||||
}
|
||||
|
||||
// Ensure these function declarations do not merge in C2x.
|
||||
|
|
|
@ -4,6 +4,6 @@ void __attribute__((ms_abi)) foo(void);
|
|||
void (*pfoo)(void) = foo;
|
||||
|
||||
void __attribute__((sysv_abi)) bar(void);
|
||||
void (*pbar)(void) = bar; // expected-warning{{incompatible function pointer types}}
|
||||
void (*pbar)(void) = bar; // expected-error{{incompatible function pointer types}}
|
||||
|
||||
void (__attribute__((sysv_abi)) *pfoo2)(void) = foo; // expected-warning{{incompatible function pointer types}}
|
||||
void (__attribute__((sysv_abi)) *pfoo2)(void) = foo; // expected-error{{incompatible function pointer types}}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
|
||||
|
||||
void __attribute__((ms_abi)) foo(void);
|
||||
void (*pfoo)(void) = foo; // expected-warning{{incompatible function pointer types}}
|
||||
void (*pfoo)(void) = foo; // expected-error{{incompatible function pointer types}}
|
||||
|
||||
void __attribute__((sysv_abi)) bar(void);
|
||||
void (*pbar)(void) = bar;
|
||||
|
||||
void (__attribute__((ms_abi)) *pbar2)(void) = bar; // expected-warning{{incompatible function pointer types}}
|
||||
void (__attribute__((ms_abi)) *pbar2)(void) = bar; // expected-error{{incompatible function pointer types}}
|
||||
|
|
|
@ -31,7 +31,7 @@ void (__attribute__((fastcall)) *pfoo)(float*) = foo;
|
|||
|
||||
void (__attribute__((stdcall)) *pbar)(float*) = bar;
|
||||
|
||||
void (__attribute__((cdecl)) *ptest1)(void) = test1; // expected-warning {{incompatible function pointer types}}
|
||||
void (__attribute__((cdecl)) *ptest1)(void) = test1; // expected-error {{incompatible function pointer types}}
|
||||
|
||||
void (*pctest0)() = ctest0;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-pointer-types -verify
|
||||
// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-function-pointer-types -verify
|
||||
// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-pointer-types -verify=hard,expected
|
||||
// RUN: %clang_cc1 -fsyntax-only %s -Wno-error=incompatible-pointer-types -verify=soft,expected
|
||||
// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-function-pointer-types -verify=hard,expected
|
||||
// RUN: %clang_cc1 -fsyntax-only %s -Wno-error=incompatible-function-pointer-types -verify=soft,expected
|
||||
|
||||
// This test ensures that the subgroup of -Wincompatible-pointer-types warnings
|
||||
// that concern function pointers can be promoted (or not promoted) to an error
|
||||
|
@ -10,5 +12,6 @@ int bar(char *a, int *b) { return 0; }
|
|||
int foo(MyFnTyA x) { return 0; } // expected-note {{passing argument to parameter 'x' here}}
|
||||
|
||||
void baz(void) {
|
||||
foo(&bar); // expected-warning {{incompatible function pointer types passing 'int (*)(char *, int *)' to parameter of type 'MyFnTyA' (aka 'int (*)(int *, char *)')}}
|
||||
foo(&bar); // soft-warning {{incompatible function pointer types passing 'int (*)(char *, int *)' to parameter of type 'MyFnTyA' (aka 'int (*)(int *, char *)')}} \
|
||||
hard-error {{incompatible function pointer types passing 'int (*)(char *, int *)' to parameter of type 'MyFnTyA' (aka 'int (*)(int *, char *)')}}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ void foo_noproto();
|
|||
void foo_noret_noproto() __attribute__((noreturn));
|
||||
|
||||
void test() {
|
||||
Fn_noret fn2 = &foo; // expected-warning {{incompatible function pointer types initializing 'Fn_noret'}}
|
||||
Fn_noret fn3 = &foo_noret;
|
||||
Fn_ret fn4 = &foo_noret;
|
||||
Fn_noret fn2 = &foo; // expected-error {{incompatible function pointer types initializing 'Fn_noret'}}
|
||||
Fn_noret fn3 = &foo_noret;
|
||||
Fn_ret fn4 = &foo_noret;
|
||||
Fn_ret fn5 = &foo;
|
||||
|
||||
Fn_noret_noproto fn6 = &foo_noproto; // expected-warning {{incompatible function pointer types initializing 'Fn_noret_noproto'}}
|
||||
Fn_noret_noproto fn7 = &foo_noret_noproto;
|
||||
Fn_ret_noproto fn8 = &foo_noret_noproto;
|
||||
Fn_noret_noproto fn6 = &foo_noproto; // expected-error {{incompatible function pointer types initializing 'Fn_noret_noproto'}}
|
||||
Fn_noret_noproto fn7 = &foo_noret_noproto;
|
||||
Fn_ret_noproto fn8 = &foo_noret_noproto;
|
||||
Fn_ret_noproto fn9 = &foo_noproto;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ void (*funcptr_nn)(__attribute__((noescape)) int *, __attribute__((noescape)) in
|
|||
void test0(int c) {
|
||||
escapefuncptr = &escapefunc;
|
||||
escapefuncptr = &noescapefunc;
|
||||
noescapefuncptr = &escapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
|
||||
noescapefuncptr = &escapefunc; // expected-error {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
|
||||
noescapefuncptr = &noescapefunc;
|
||||
|
||||
escapefuncptr = c ? &escapefunc : &noescapefunc;
|
||||
noescapefuncptr = c ? &escapefunc : &noescapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
|
||||
noescapefuncptr = c ? &escapefunc : &noescapefunc; // expected-error {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
|
||||
|
||||
funcptr_ee = c ? &func_ne : &func_en;
|
||||
funcptr_nn = c ? &func_ne : &func_en; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *, __attribute__((noescape)) int *)' from 'void (*)(int *, int *)'}}
|
||||
funcptr_nn = c ? &func_ne : &func_en; // expected-error {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *, __attribute__((noescape)) int *)' from 'void (*)(int *, int *)'}}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ void fn_type_conversions() {
|
|||
void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
|
||||
void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type '<overloaded function type>'}} expected-note@-5{{candidate function}} expected-note@-4{{candidate function}}
|
||||
|
||||
void (*specific1)(int *) = (void (*)(void *))&foo; // expected-warning{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type 'void (*)(void *)'}}
|
||||
void (*specific1)(int *) = (void (*)(void *))&foo; // expected-error{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type 'void (*)(void *)'}}
|
||||
void *specific2 = (void (*)(void *))&foo;
|
||||
|
||||
void disabled(void *c) __attribute__((overloadable, enable_if(0, "")));
|
||||
|
@ -120,8 +120,8 @@ void fn_type_conversions() {
|
|||
void disabled(char *c) __attribute__((overloadable, enable_if(1, "The function name lies.")));
|
||||
// To be clear, these should all point to the last overload of 'disabled'
|
||||
void (*dptr1)(char *c) = &disabled;
|
||||
void (*dptr2)(void *c) = &disabled; // expected-warning{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function made ineligible by enable_if}} expected-note@-3{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
|
||||
void (*dptr3)(int *c) = &disabled; // expected-warning{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@-6{{candidate function made ineligible by enable_if}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
|
||||
void (*dptr2)(void *c) = &disabled; // expected-error{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function made ineligible by enable_if}} expected-note@-3{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
|
||||
void (*dptr3)(int *c) = &disabled; // expected-error{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@-6{{candidate function made ineligible by enable_if}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
|
||||
|
||||
void *specific_disabled = &disabled;
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ void FunctionPtrs(void) {
|
|||
void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
|
||||
void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
|
||||
|
||||
void (*p3)(void *) = IsOverloaded; //expected-warning{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
|
||||
void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
|
||||
void (*p3)(void *) = IsOverloaded; //expected-error{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
|
||||
void (*p4)(void *) = &IsOverloaded; //expected-error{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}}
|
||||
|
||||
void (*p5)(char *) = IsOverloaded;
|
||||
void (*p6)(char *) = &IsOverloaded;
|
||||
|
|
|
@ -14,8 +14,8 @@ void __attribute__((preserve_most(1))) foo1(void *ptr) { // expected-error {{'pr
|
|||
|
||||
void (__attribute__((preserve_most)) *pfoo1)(void *) = foo;
|
||||
|
||||
void (__attribute__((cdecl)) *pfoo2)(void *) = foo; // expected-warning {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
|
||||
void (*pfoo3)(void *) = foo; // expected-warning {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
|
||||
void (__attribute__((cdecl)) *pfoo2)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
|
||||
void (*pfoo3)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
|
||||
|
||||
typedef_fun_t typedef_fun_foo; // expected-note {{previous declaration is here}}
|
||||
void __attribute__((preserve_most)) typedef_fun_foo(int x) { } // expected-error {{function declared 'preserve_most' here was previously declared without calling convention}}
|
||||
|
@ -30,8 +30,8 @@ void __attribute__((preserve_all(1))) boo1(void *ptr) { // expected-error {{'pre
|
|||
|
||||
void (__attribute__((preserve_all)) *pboo1)(void *) = boo;
|
||||
|
||||
void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-warning {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
|
||||
void (*pboo3)(void *) = boo; // expected-warning {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
|
||||
void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
|
||||
void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
|
||||
|
||||
typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}}
|
||||
void __attribute__((preserve_all)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_all' here was previously declared without calling convention}}
|
||||
|
|
|
@ -31,9 +31,9 @@ typedef id FuncSignature (NSObject *arg1, Derived *arg2);
|
|||
|
||||
void foo(void)
|
||||
{
|
||||
// GCC currently allows this (it has some fiarly new support for covariant return types and contravariant argument types).
|
||||
// GCC currently allows this (it has some fairly new support for covariant return types and contravariant argument types).
|
||||
// Since registerFunc: expects a Derived object as it's second argument, I don't know why this would be legal.
|
||||
[Derived registerFunc: ExternFunc]; // expected-warning{{incompatible function pointer types sending 'NSObject *(NSObject *, NSObject *)' to parameter of type 'FuncSignature *' (aka 'id (*)(NSObject *, Derived *)')}}
|
||||
[Derived registerFunc: ExternFunc]; // expected-error{{incompatible function pointer types sending 'NSObject *(NSObject *, NSObject *)' to parameter of type 'FuncSignature *' (aka 'id (*)(NSObject *, Derived *)')}}
|
||||
}
|
||||
|
||||
// rdar://10751015
|
||||
|
|
Loading…
Reference in New Issue