give better diagnostics for converting between function pointer and void*.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45556 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/Sema.h b/Sema/Sema.h
index 7faac13..33fd345 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -612,6 +612,7 @@
Incompatible,
PointerFromInt,
IntFromPointer,
+ FunctionVoidPointer,
IncompatiblePointer,
CompatiblePointerDiscardsQualifiers
};
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 5a58839..1165e52 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -394,6 +394,11 @@
DeclType.getAsString(), rhsType.getAsString(),
Init->getSourceRange());
break;
+ case FunctionVoidPointer:
+ Diag(Init->getLocStart(), diag::ext_typecheck_assign_pointer_void_func,
+ DeclType.getAsString(), rhsType.getAsString(),
+ Init->getSourceRange());
+ break;
case IncompatiblePointer:
Diag(Init->getLocStart(), diag::ext_typecheck_assign_incompatible_pointer,
DeclType.getAsString(), rhsType.getAsString(),
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
index 1ec60d9..68c301a 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -644,6 +644,11 @@
LHSType.getAsString(), RHSType.getAsString(),
Fn->getSourceRange(), Arg->getSourceRange());
break;
+ case FunctionVoidPointer:
+ Diag(Loc, diag::ext_typecheck_passing_pointer_void_func,
+ LHSType.getAsString(), RHSType.getAsString(),
+ Fn->getSourceRange(), Arg->getSourceRange());
+ break;
case IncompatiblePointer:
Diag(Loc, diag::ext_typecheck_passing_incompatible_pointer,
RHSType.getAsString(), LHSType.getAsString(),
@@ -1075,17 +1080,29 @@
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
// incomplete type and the other is a pointer to a qualified or unqualified
// version of void...
- if (lhptee.getUnqualifiedType()->isVoidType() &&
- (rhptee->isObjectType() || rhptee->isIncompleteType()))
- ;
- else if (rhptee.getUnqualifiedType()->isVoidType() &&
- (lhptee->isObjectType() || lhptee->isIncompleteType()))
- ;
+ if (lhptee->isVoidType()) {
+ if (rhptee->isObjectType() || rhptee->isIncompleteType())
+ return r;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ if (rhptee->isFunctionType())
+ return FunctionVoidPointer;
+ }
+
+ if (rhptee->isVoidType()) {
+ if (lhptee->isObjectType() || lhptee->isIncompleteType())
+ return r;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ if (lhptee->isFunctionType())
+ return FunctionVoidPointer;
+ }
+
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
- else if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
- rhptee.getUnqualifiedType()))
- r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
+ if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType()))
+ return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
return r;
}
@@ -1543,6 +1560,11 @@
lhsType.getAsString(), rhsType.getAsString(),
lex->getSourceRange(), rex->getSourceRange());
break;
+ case FunctionVoidPointer:
+ Diag(loc, diag::ext_typecheck_assign_pointer_void_func,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ break;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer,
lhsType.getAsString(), rhsType.getAsString(),
@@ -2226,6 +2248,11 @@
rhsType.getAsString(), lhsType.getAsString(),
argExpr->getSourceRange());
break;
+ case FunctionVoidPointer:
+ Diag(l, diag::ext_typecheck_sending_pointer_void_func,
+ rhsType.getAsString(), lhsType.getAsString(),
+ argExpr->getSourceRange());
+ break;
case CompatiblePointerDiscardsQualifiers:
Diag(l, diag::ext_typecheck_passing_discards_qualifiers,
rhsType.getAsString(), lhsType.getAsString(),
diff --git a/Sema/SemaStmt.cpp b/Sema/SemaStmt.cpp
index cbb01bd..2c2dc5e 100644
--- a/Sema/SemaStmt.cpp
+++ b/Sema/SemaStmt.cpp
@@ -663,6 +663,11 @@
lhsType.getAsString(), rhsType.getAsString(),
RetValExp->getSourceRange());
break;
+ case FunctionVoidPointer:
+ Diag(ReturnLoc, diag::ext_typecheck_return_pointer_void_func,
+ lhsType.getAsString(), rhsType.getAsString(),
+ RetValExp->getSourceRange());
+ break;
case IncompatiblePointer:
Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer,
lhsType.getAsString(), rhsType.getAsString(),
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 591e305..0f31c92 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -767,6 +767,8 @@
"incompatible pointer types assigning '%1' to '%0'")
DIAG(ext_typecheck_assign_discards_qualifiers, WARNING,
"assigning '%1' to '%0' discards qualifiers")
+DIAG(ext_typecheck_assign_pointer_void_func, EXTENSION,
+ "assigning '%1' to '%0' converts between void* and function pointer")
DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
"array type '%0' is not assignable")
DIAG(err_typecheck_non_object_not_modifiable_lvalue, ERROR,
@@ -791,6 +793,9 @@
"incompatible pointer types passing '%0' to function expecting '%1'")
DIAG(ext_typecheck_passing_pointer_int, WARNING,
"incompatible types passing '%1' to function expecting '%0'")
+DIAG(ext_typecheck_passing_pointer_void_func, EXTENSION,
+ "passing '%1' to function expecting '%0' converts between void*"
+ " and function pointer")
DIAG(ext_typecheck_passing_discards_qualifiers, WARNING,
"passing '%0' to '%1' discards qualifiers")
DIAG(err_typecheck_sending_incompatible, ERROR,
@@ -799,6 +804,9 @@
"incompatible pointer types passing '%0' to method expecting '%1'")
DIAG(ext_typecheck_sending_pointer_int, WARNING,
"incompatible types passing '%1' to method expecting '%0'")
+DIAG(ext_typecheck_sending_pointer_void_func, EXTENSION,
+ "sending '%1' to method expecting '%0' converts between void*"
+ " and function pointer")
DIAG(err_typecheck_cond_expect_scalar, ERROR,
"used type '%0' where arithmetic or pointer type is required")
DIAG(err_typecheck_expect_scalar_operand, ERROR,
@@ -909,6 +917,9 @@
"incompatible type returning '%1', expected '%0'")
DIAG(ext_typecheck_return_pointer_int, EXTENSION,
"incompatible type returning '%1', expected '%0'")
+DIAG(ext_typecheck_return_pointer_void_func, EXTENSION,
+ "returning '%1' to from function expecting '%0' converts between void*"
+ " and function pointer")
DIAG(ext_typecheck_return_incompatible_pointer, EXTENSION,
"incompatible pointer type returning '%1', expected '%0'")
DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION,
diff --git a/test/Sema/function-ptr.c b/test/Sema/function-ptr.c
new file mode 100644
index 0000000..83e4d74
--- /dev/null
+++ b/test/Sema/function-ptr.c
@@ -0,0 +1,11 @@
+// RUN: clang %s -verify -pedantic
+typedef int unary_int_func(int arg);
+unary_int_func *func;
+
+unary_int_func *set_func(void *p) {
+ func = p; // expected-warning {{converts between void* and function pointer}}
+ p = func; // expected-warning {{converts between void* and function pointer}}
+
+ return p; // expected-warning {{converts between void* and function pointer}}
+}
+