[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