[cfe-commits] r55767 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/Basic/DiagnosticKinds.def lib/AST/ASTContext.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp
Steve Naroff
snaroff at apple.com
Thu Sep 4 08:10:53 PDT 2008
Author: snaroff
Date: Thu Sep 4 10:10:53 2008
New Revision: 55767
URL: http://llvm.org/viewvc/llvm-project?rev=55767&view=rev
Log:
Add type checking for blocks.
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=55767&r1=55766&r2=55767&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Sep 4 10:10:53 2008
@@ -416,6 +416,7 @@
/// Compatibility predicates used to check assignment expressions.
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ bool typesAreBlockCompatible(QualType lhs, QualType rhs);
bool isObjCIdType(QualType T) const {
if (!IdStructType) // ObjC isn't enabled
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=55767&r1=55766&r2=55767&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Thu Sep 4 10:10:53 2008
@@ -998,6 +998,14 @@
"incompatible pointer types %2 '%1', expected '%0'")
DIAG(ext_typecheck_convert_discards_qualifiers, EXTWARN,
"%2 '%1' discards qualifiers, expected '%0'")
+DIAG(err_int_to_block_pointer, ERROR,
+ "invalid conversion %2 integer '%1', expected block pointer '%0'")
+DIAG(err_typecheck_comparison_of_distinct_blocks, ERROR,
+ "comparison of distinct block types ('%0' and '%1')")
+DIAG(err_typecheck_convert_incompatible_block_pointer, ERROR,
+ "incompatible block pointer types %2 '%1', expected '%0'")
+DIAG(ext_typecheck_convert_pointer_void_block, EXTENSION,
+ "%2 '%1' converts between void* and block pointer, expected '%0'")
DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
"array type '%0' is not assignable")
@@ -1133,7 +1141,7 @@
DIAG(err_expected_block_lbrace, ERROR,
"expected '{' in block literal")
DIAG(err_goto_in_block, ERROR,
- "goto not allowed in closure literal")
+ "goto not allowed in block literal")
DIAG(err_return_in_block_expression, ERROR,
"return not allowed in block expression literal")
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=55767&r1=55766&r2=55767&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Sep 4 10:10:53 2008
@@ -1767,6 +1767,52 @@
// Type Compatibility Testing
//===----------------------------------------------------------------------===//
+/// typesAreBlockCompatible - This routine is called when comparing two
+/// closure types. Types must be strictly compatible here.
+bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
+ if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
+ return false;
+
+ QualType lcanon = getCanonicalType(lhs);
+ QualType rcanon = getCanonicalType(rhs);
+
+ // If two types are identical, they are are compatible
+ if (lcanon == rcanon)
+ return true;
+ if (isa<FunctionType>(lcanon) && isa<FunctionType>(rcanon)) {
+ const FunctionType *lbase = cast<FunctionType>(lcanon);
+ const FunctionType *rbase = cast<FunctionType>(rcanon);
+
+ // First check the return types.
+ if (!typesAreBlockCompatible(lbase->getResultType(),rbase->getResultType()))
+ return false;
+
+ // Return types matched, now check the argument types.
+ const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
+ const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
+
+ if (lproto && rproto) { // two C99 style function prototypes
+ unsigned lproto_nargs = lproto->getNumArgs();
+ unsigned rproto_nargs = rproto->getNumArgs();
+
+ if (lproto_nargs != rproto_nargs)
+ return false;
+
+ if (lproto->isVariadic() || rproto->isVariadic())
+ return false;
+
+ // The use of ellipsis agree...now check the argument types.
+ for (unsigned i = 0; i < lproto_nargs; i++)
+ if (!typesAreBlockCompatible(lproto->getArgType(i),
+ rproto->getArgType(i)))
+ return false;
+ return true;
+ }
+ return (!lproto && !rproto); // two K&R style function decls match.
+ }
+ return false;
+}
+
/// areCompatVectorTypes - Return true if the two specified vector types are
/// compatible.
static bool areCompatVectorTypes(const VectorType *LHS,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=55767&r1=55766&r2=55767&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep 4 10:10:53 2008
@@ -816,6 +816,18 @@
/// CompatiblePointerDiscardsQualifiers - The assignment discards
/// c/v/r qualifiers, which we accept as an extension.
CompatiblePointerDiscardsQualifiers,
+
+ /// IntToBlockPointer - The assignment converts an int to a closure
+ /// pointer. We disallow this.
+ IntToBlockPointer,
+
+ /// IncompatibleBlockPointer - The assignment is between two closure
+ /// pointers types that are not compatible.
+ IncompatibleBlockPointer,
+
+ /// BlockVoidPointer - The assignment is between a closure pointer and
+ /// void*, we accept for now.
+ BlockVoidPointer,
/// Incompatible - We reject this conversion outright, it is invalid to
/// represent it in the AST.
@@ -849,6 +861,11 @@
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
+
+ // Helper function for CheckAssignmentConstraints involving two
+ // blcok pointer types.
+ AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=55767&r1=55766&r2=55767&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 4 10:10:53 2008
@@ -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;
More information about the cfe-commits
mailing list