Add type checking for blocks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55767 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 14fec20..37172cb 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1431,6 +1431,34 @@
return ConvTy;
}
+/// CheckBlockPointerTypesForAssignment - This routine determines whether two
+/// block pointer types are compatible or whether a block and normal pointer
+/// are compatible. It is more restrict than comparing two function pointer
+// types.
+Sema::AssignConvertType
+Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType) {
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type (ignoring qualifiers at the top level)
+ lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
+ rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
+
+ // make sure we operate on the canonical type
+ lhptee = Context.getCanonicalType(lhptee);
+ rhptee = Context.getCanonicalType(rhptee);
+
+ AssignConvertType ConvTy = Compatible;
+
+ // For blocks we enforce that qualifiers are identical.
+ if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
+ ConvTy = CompatiblePointerDiscardsQualifiers;
+
+ if (!Context.typesAreBlockCompatible(lhptee, rhptee))
+ return IncompatibleBlockPointer;
+ return ConvTy;
+}
+
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
/// has code to accommodate several GCC extensions when type checking
/// pointers. Here are some objectionable examples that GCC considers warnings:
@@ -1500,6 +1528,25 @@
if (isa<PointerType>(rhsType))
return CheckPointerTypesForAssignment(lhsType, rhsType);
+
+ if (const BlockPointerType *BPT = rhsType->getAsBlockPointerType())
+ if (BPT->getPointeeType()->isVoidType())
+ return BlockVoidPointer;
+
+ return Incompatible;
+ }
+
+ if (isa<BlockPointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ if (rhsType->isBlockPointerType())
+ return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
+
+ if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+ if (RHSPT->getPointeeType()->isVoidType())
+ return BlockVoidPointer;
+ }
return Incompatible;
}
@@ -1513,6 +1560,10 @@
if (isa<PointerType>(lhsType))
return CheckPointerTypesForAssignment(lhsType, rhsType);
+
+ if (isa<BlockPointerType>(lhsType) &&
+ rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ return BlockVoidPointer;
return Incompatible;
}
@@ -1532,6 +1583,11 @@
ImpCastExprToType(rExpr, lhsType);
return Compatible;
}
+
+ // We don't allow conversion of non-null-pointer constants to integers.
+ if (lhsType->isBlockPointerType() && rExpr->getType()->isIntegerType())
+ return IntToBlockPointer;
+
// This check seems unnatural, however it is necessary to ensure the proper
// conversion of functions/arrays. If the conversion were done for all
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
@@ -1849,6 +1905,21 @@
ImpCastExprToType(rex, lType); // promote the pointer to pointer
return Context.IntTy;
}
+ // Handle block pointer types.
+ if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
+ QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
+ QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
+
+ if (!LHSIsNull && !RHSIsNull &&
+ !Context.typesAreBlockCompatible(lpointee, rpointee)) {
+ Diag(loc, diag::err_typecheck_comparison_of_distinct_blocks,
+ lType.getAsString(), rType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ }
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ return Context.IntTy;
+ }
+
if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
ImpCastExprToType(rex, lType);
@@ -2875,6 +2946,15 @@
case CompatiblePointerDiscardsQualifiers:
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
break;
+ case IntToBlockPointer:
+ DiagKind = diag::err_int_to_block_pointer;
+ break;
+ case IncompatibleBlockPointer:
+ DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
+ break;
+ case BlockVoidPointer:
+ DiagKind = diag::ext_typecheck_convert_pointer_void_block;
+ break;
case Incompatible:
DiagKind = diag::err_typecheck_convert_incompatible;
isInvalid = true;