Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -78,6 +78,10 @@ - ``-Wformat`` now recognizes ``%b`` for the ``printf``/``scanf`` family of functions and ``%B`` for the ``printf`` family of functions. Fixes `Issue 56885: `_. +- ``-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 ------------------------------------------------- Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8157,24 +8157,6 @@ "; 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; 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 @@ "; take the address with &|" "; remove *|" "; remove &}3">; +def ext_typecheck_convert_incompatible_function_pointer : ExtWarn< + err_typecheck_convert_incompatible_function_pointer.Text>, + InGroup, 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 $|" Index: clang/test/CodeGen/attributes.c =================================================================== --- clang/test/CodeGen/attributes.c +++ clang/test/CodeGen/attributes.c @@ -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; Index: clang/test/CodeGen/overloadable.c =================================================================== --- clang/test/CodeGen/overloadable.c +++ clang/test/CodeGen/overloadable.c @@ -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 Index: clang/test/Sema/aarch64-svepcs.c =================================================================== --- clang/test/Sema/aarch64-svepcs.c +++ clang/test/Sema/aarch64-svepcs.c @@ -15,5 +15,5 @@ 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}} } Index: clang/test/Sema/aarch64-vpcs.c =================================================================== --- clang/test/Sema/aarch64-vpcs.c +++ clang/test/Sema/aarch64-vpcs.c @@ -15,5 +15,5 @@ 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}} } Index: clang/test/Sema/arm-cmse.c =================================================================== --- clang/test/Sema/arm-cmse.c +++ clang/test/Sema/arm-cmse.c @@ -8,8 +8,8 @@ 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; } Index: clang/test/Sema/attr-nocf_check.c =================================================================== --- clang/test/Sema/attr-nocf_check.c +++ clang/test/Sema/attr-nocf_check.c @@ -15,7 +15,7 @@ // 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 } Index: clang/test/Sema/block-return.c =================================================================== --- clang/test/Sema/block-return.c +++ clang/test/Sema/block-return.c @@ -81,7 +81,7 @@ 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; }; } Index: clang/test/Sema/c2x-func-prototype.c =================================================================== --- clang/test/Sema/c2x-func-prototype.c +++ clang/test/Sema/c2x-func-prototype.c @@ -13,7 +13,7 @@ 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. Index: clang/test/Sema/callingconv-ms_abi.c =================================================================== --- clang/test/Sema/callingconv-ms_abi.c +++ clang/test/Sema/callingconv-ms_abi.c @@ -4,6 +4,6 @@ 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}} Index: clang/test/Sema/callingconv-sysv_abi.c =================================================================== --- clang/test/Sema/callingconv-sysv_abi.c +++ clang/test/Sema/callingconv-sysv_abi.c @@ -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}} Index: clang/test/Sema/callingconv.c =================================================================== --- clang/test/Sema/callingconv.c +++ clang/test/Sema/callingconv.c @@ -31,7 +31,7 @@ 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; Index: clang/test/Sema/incompatible-function-pointer-types.c =================================================================== --- clang/test/Sema/incompatible-function-pointer-types.c +++ clang/test/Sema/incompatible-function-pointer-types.c @@ -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 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 *)')}} } Index: clang/test/Sema/initialize-noreturn.c =================================================================== --- clang/test/Sema/initialize-noreturn.c +++ clang/test/Sema/initialize-noreturn.c @@ -14,14 +14,14 @@ 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; } Index: clang/test/Sema/noescape.c =================================================================== --- clang/test/Sema/noescape.c +++ clang/test/Sema/noescape.c @@ -14,12 +14,12 @@ 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 *)'}} } Index: clang/test/Sema/overloadable.c =================================================================== --- clang/test/Sema/overloadable.c +++ clang/test/Sema/overloadable.c @@ -112,7 +112,7 @@ void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible 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 ''}} 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 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 ''}} 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 ''}} 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 ''}} 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 ''}} 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; } Index: clang/test/Sema/pass-object-size.c =================================================================== --- clang/test/Sema/pass-object-size.c +++ clang/test/Sema/pass-object-size.c @@ -44,8 +44,8 @@ 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 ''}} - void (*p4)(void *) = &IsOverloaded; //expected-warning{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type ''}} + void (*p3)(void *) = IsOverloaded; //expected-error{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type ''}} + void (*p4)(void *) = &IsOverloaded; //expected-error{{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type ''}} void (*p5)(char *) = IsOverloaded; void (*p6)(char *) = &IsOverloaded; Index: clang/test/Sema/preserve-call-conv.c =================================================================== --- clang/test/Sema/preserve-call-conv.c +++ clang/test/Sema/preserve-call-conv.c @@ -14,8 +14,8 @@ 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)) *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}} Index: clang/test/SemaObjC/comptypes-legal.m =================================================================== --- clang/test/SemaObjC/comptypes-legal.m +++ clang/test/SemaObjC/comptypes-legal.m @@ -31,9 +31,9 @@ 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