aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Sema/Sema.h1
-rw-r--r--Sema/SemaDecl.cpp5
-rw-r--r--Sema/SemaExpr.cpp45
-rw-r--r--Sema/SemaStmt.cpp5
-rw-r--r--include/clang/Basic/DiagnosticKinds.def11
-rw-r--r--test/Sema/function-ptr.c11
6 files changed, 69 insertions, 9 deletions
diff --git a/Sema/Sema.h b/Sema/Sema.h
index 7faac13458..33fd345d00 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -612,6 +612,7 @@ private:
Incompatible,
PointerFromInt,
IntFromPointer,
+ FunctionVoidPointer,
IncompatiblePointer,
CompatiblePointerDiscardsQualifiers
};
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 5a588397d9..1165e526d8 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -394,6 +394,11 @@ bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic,
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 1ec60d9934..68c301afd8 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -644,6 +644,11 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
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 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
// 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 @@ inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1
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 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
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 cbb01bdb3c..2c2dc5e3f0 100644
--- a/Sema/SemaStmt.cpp
+++ b/Sema/SemaStmt.cpp
@@ -663,6 +663,11 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
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 591e3059a8..0f31c922cf 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -767,6 +767,8 @@ DIAG(ext_typecheck_assign_incompatible_pointer, WARNING,
"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 @@ DIAG(ext_typecheck_passing_incompatible_pointer, WARNING,
"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 @@ DIAG(ext_typecheck_sending_incompatible_pointer, WARNING,
"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 @@ DIAG(err_typecheck_return_incompatible, ERROR,
"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 0000000000..83e4d74b6a
--- /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}}
+}
+