Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -224,9 +224,12 @@ def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">; def IncompatiblePointerTypesDiscardsQualifiers : DiagGroup<"incompatible-pointer-types-discards-qualifiers">; +def IncompatibleFunctionPointerTypes + : DiagGroup<"incompatible-function-pointer-types">; def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types", - [IncompatiblePointerTypesDiscardsQualifiers]>; + [IncompatiblePointerTypesDiscardsQualifiers, + IncompatibleFunctionPointerTypes]>; def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; def NonModularIncludeInFrameworkModule : DiagGroup<"non-modular-include-in-framework-module">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6344,6 +6344,24 @@ "; remove *|" "; remove &}3">, InGroup; +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 ext_typecheck_convert_discards_qualifiers : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12420,10 +12420,14 @@ MayHaveConvFixit = true; break; case IncompatiblePointer: - DiagKind = - (Action == AA_Passing_CFAudited ? - diag::err_arc_typecheck_convert_incompatible_pointer : - diag::ext_typecheck_convert_incompatible_pointer); + if (Action == AA_Passing_CFAudited) + DiagKind = diag::err_arc_typecheck_convert_incompatible_pointer; + else if (SrcType->isFunctionPointerType() && + DstType->isFunctionPointerType()) + DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer; + else + DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); if (Hint.isNull() && !CheckInferredResultType) { Index: test/Sema/incompatible-function-pointer-types.c =================================================================== --- /dev/null +++ test/Sema/incompatible-function-pointer-types.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-pointer-types -verify +// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-function-pointer-types -verify + +// This test ensures that the subgroup of -Wincompatible-pointer-types warnings +// that concern function pointers can be promoted (or not promoted) to an error +// *separately* from the other -Wincompatible-pointer-type warnings. +typedef int (*MyFnTyA)(int *, char *); + +int bar(char *a, int *b) { return 0; } +int foo(MyFnTyA x) { return 0; } // expected-note {{passing argument to parameter 'x' here}} + +void baz() { + foo(&bar); // expected-warning {{incompatible function pointer types passing 'int (*)(char *, int *)' to parameter of type 'MyFnTyA' (aka 'int (*)(int *, char *)')}} +} Index: test/Sema/initialize-noreturn.c =================================================================== --- test/Sema/initialize-noreturn.c +++ test/Sema/initialize-noreturn.c @@ -8,7 +8,7 @@ void foo_noret(void) __attribute__((noreturn)); void test() { - Fn_noret fn2 = &foo; // expected-warning {{incompatible pointer types initializing 'Fn_noret'}} + Fn_noret fn2 = &foo; // expected-warning {{incompatible function pointer types initializing 'Fn_noret'}} Fn_noret fn3 = &foo_noret; Fn_ret fn4 = &foo_noret; Fn_ret fn5 = &foo; Index: test/Sema/overloadable.c =================================================================== --- test/Sema/overloadable.c +++ test/Sema/overloadable.c @@ -109,7 +109,7 @@ void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type ''}} expected-note@105{{candidate function}} expected-note@106{{candidate function}} void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type ''}} expected-note@105{{candidate function}} expected-note@106{{candidate function}} - void (*specific1)(int *) = (void (*)(void *))&foo; // expected-warning{{incompatible pointer types initializing 'void (*)(int *)' with an expression of type 'void (*)(void *)'}} + void (*specific1)(int *) = (void (*)(void *))&foo; // expected-warning{{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, "")));