[cfe-commits] r55862 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/AST/ASTContext.cpp lib/AST/Expr.cpp lib/Sema/SemaChecking.cpp lib/Sema/SemaExpr.cpp test/Sema/block-call.c test/Sema/block-misc.c

Steve Naroff snaroff at apple.com
Fri Sep 5 15:11:14 PDT 2008


Author: snaroff
Date: Fri Sep  5 17:11:13 2008
New Revision: 55862

URL: http://llvm.org/viewvc/llvm-project?rev=55862&view=rev
Log:
More type checking for blocks. Still incomplete (will hopefully finish up this weekend).

Added:
    cfe/trunk/test/Sema/block-call.c
    cfe/trunk/test/Sema/block-misc.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=55862&r1=55861&r2=55862&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Fri Sep  5 17:11:13 2008
@@ -1022,8 +1022,14 @@
      "called object is not a function or function pointer")
 DIAG(err_typecheck_call_too_few_args, ERROR,
      "too few arguments to function")
+DIAG(err_typecheck_block_too_few_args, ERROR,
+     "too few arguments to block")
 DIAG(err_typecheck_call_too_many_args, ERROR,
      "too many arguments to function")
+DIAG(err_typecheck_block_too_many_args, ERROR,
+     "too many arguments to block call")
+DIAG(err_typecheck_closure_too_many_args, ERROR,
+     "too many arguments to closure call")
 DIAG(err_typecheck_call_invalid_ordered_compare, ERROR,
      "ordered compare requires two args of floating point type ('%0' and '%1')")
 DIAG(err_typecheck_cond_expect_scalar, ERROR,
@@ -1145,6 +1151,9 @@
 DIAG(err_return_in_block_expression, ERROR,
      "return not allowed in block expression literal")
 
+DIAG(err_ret_local_block, ERROR,
+     "returning block that lives on the local stack")
+
 // CFString checking
 DIAG(err_cfstring_literal_not_string_constant, ERROR,
   "CFString literal is not a string constant")

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=55862&r1=55861&r2=55862&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Sep  5 17:11:13 2008
@@ -1781,7 +1781,19 @@
 //===----------------------------------------------------------------------===//
 
 /// typesAreBlockCompatible - This routine is called when comparing two
-/// block types. Types must be strictly compatible here.
+/// block types. Types must be strictly compatible here. For example,
+/// C unfortunately doesn't produce an error for the following:
+/// 
+///   int (*emptyArgFunc)();
+///   int (*intArgList)(int) = emptyArgFunc;
+/// 
+/// For blocks, we will produce an error for the following (similar to C++):
+///
+///   int (^emptyArgBlock)();
+///   int (^intArgBlock)(int) = emptyArgBlock;
+///
+/// FIXME: When the dust settles on this integration, fold this into mergeTypes.
+///
 bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
   if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
     return false;

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=55862&r1=55861&r2=55862&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Sep  5 17:11:13 2008
@@ -423,6 +423,12 @@
       return LV_Valid;
     break;
   }
+  case BlockDeclRefExprClass: {
+    const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
+    if (BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
+      return LV_Valid;
+    break;
+  }
   case MemberExprClass: { // C99 6.5.2.3p4
     const MemberExpr *m = cast<MemberExpr>(this);
     return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
@@ -1453,4 +1459,6 @@
 Stmt::child_iterator BlockExprExpr::child_end() {
   return reinterpret_cast<Stmt**>(&BodyExpr)+1;
 }
+Stmt::child_iterator BlockDeclRefExpr::child_begin(){return child_iterator();}
+Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator();}
 

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=55862&r1=55861&r2=55862&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Sep  5 17:11:13 2008
@@ -711,11 +711,15 @@
                            SourceLocation ReturnLoc) {
    
   // Perform checking for returned stack addresses.
-  if (lhsType->isPointerType()) {
+  if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
     if (DeclRefExpr *DR = EvalAddr(RetValExp))
       Diag(DR->getLocStart(), diag::warn_ret_stack_addr,
            DR->getDecl()->getIdentifier()->getName(),
            RetValExp->getSourceRange());
+           
+    if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(EvalAddr(RetValExp)))
+      Diag(C->getLocStart(), diag::err_ret_local_block,
+           C->getSourceRange());
   }
   // Perform checking for stack values returned by reference.
   else if (lhsType->isReferenceType()) {
@@ -751,7 +755,8 @@
 ///   * taking the address of an array element where the array is on the stack
 static DeclRefExpr* EvalAddr(Expr *E) {
   // We should only be called for evaluating pointer expressions.
-  assert((E->getType()->isPointerType() || 
+  assert((E->getType()->isPointerType() ||
+          E->getType()->isBlockPointerType() ||
           E->getType()->isObjCQualifiedIdType()) &&
          "EvalAddr only works on pointers");
     
@@ -814,7 +819,9 @@
     Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
     QualType T = SubExpr->getType();
     
-    if (T->isPointerType() || T->isObjCQualifiedIdType())
+    if (SubExpr->getType()->isPointerType() ||
+        SubExpr->getType()->isBlockPointerType() ||
+        SubExpr->getType()->isObjCQualifiedIdType())
       return EvalAddr(SubExpr);
     else if (T->isArrayType())
       return EvalVal(SubExpr);
@@ -832,7 +839,7 @@
     
     if (C->getOpcode() == CXXCastExpr::ReinterpretCast) {
       Expr *S = C->getSubExpr();
-      if (S->getType()->isPointerType())
+      if (S->getType()->isPointerType() || S->getType()->isBlockPointerType())
         return EvalAddr(S);
       else
         return NULL;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=55862&r1=55861&r2=55862&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Sep  5 17:11:13 2008
@@ -299,6 +299,24 @@
                            StringToks[NumStringToks-1].getLocation());
 }
 
+/// DeclDefinedWithinScope - Return true if the specified decl is defined at or
+/// within the 'Within' scope.  The current Scope is CurScope.
+///
+/// NOTE: This method is extremely inefficient (linear scan), this should not be
+/// used in common cases.
+///
+static bool DeclDefinedWithinScope(ScopedDecl *D, Scope *Within,
+                                   Scope *CurScope) {
+  while (1) {
+    assert(CurScope && "CurScope not nested within 'Within'?");
+
+    // Check this scope for the decl.
+    if (CurScope->isDeclScope(D)) return true;
+    
+    if (CurScope == Within) return false;
+    CurScope = CurScope->getParent();
+  }
+}
 
 /// ActOnIdentifierExpr - The parser read an identifier in expression context,
 /// validate it per-C99 6.5.1.  HasTrailingLParen indicates whether this
@@ -350,17 +368,6 @@
     }
   }
   
-  if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
-    // check if referencing an identifier with __attribute__((deprecated)).
-    if (VD->getAttr<DeprecatedAttr>())
-      Diag(Loc, diag::warn_deprecated, VD->getName());
-
-    // Only create DeclRefExpr's for valid Decl's.
-    if (VD->isInvalidDecl())
-      return true;
-    return new DeclRefExpr(VD, VD->getType(), Loc);
-  }
-
   if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) {
     if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
       if (MD->isStatic())
@@ -383,7 +390,6 @@
 
     return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());
   }
-  
   if (isa<TypedefDecl>(D))
     return Diag(Loc, diag::err_unexpected_typedef, II.getName());
   if (isa<ObjCInterfaceDecl>(D))
@@ -391,8 +397,36 @@
   if (isa<NamespaceDecl>(D))
     return Diag(Loc, diag::err_unexpected_namespace, II.getName());
 
-  assert(0 && "Invalid decl");
-  abort();
+  // Make the DeclRefExpr or BlockDeclRefExpr for the decl.
+  ValueDecl *VD = cast<ValueDecl>(D);
+  
+  // check if referencing an identifier with __attribute__((deprecated)).
+  if (VD->getAttr<DeprecatedAttr>())
+    Diag(Loc, diag::warn_deprecated, VD->getName());
+
+  // Only create DeclRefExpr's for valid Decl's.
+  if (VD->isInvalidDecl())
+    return true;
+    
+  // If this reference is not in a block or if the referenced variable is
+  // within the block, create a normal DeclRefExpr.
+  //
+  // FIXME: This will create BlockDeclRefExprs for global variables,
+  // function references, enums constants, etc which is suboptimal :) and breaks
+  // things like "integer constant expression" tests.
+  //
+  if (!CurBlock || DeclDefinedWithinScope(VD, CurBlock->TheScope, S))
+    return new DeclRefExpr(VD, VD->getType(), Loc);
+  
+  // If we are in a block and the variable is outside the current block,
+  // bind the variable reference with a BlockDeclRefExpr.
+  
+  // If the variable is in the byref set, bind it directly, otherwise it will be
+  // bound by-copy, thus we make it const within the closure.
+  if (!CurBlock->ByRefVars.count(VD))
+    VD->getType().addConst();
+    
+  return new BlockDeclRefExpr(VD, VD->getType(), Loc, false);
 }
 
 Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -983,14 +1017,19 @@
   // of arguments and function on error.
   llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,
                                                  Context.BoolTy, RParenLoc));
-  
-  // C99 6.5.2.2p1 - "The expression that denotes the called function shall have
-  // type pointer to function".
-  const PointerType *PT = Fn->getType()->getAsPointerType();
-  if (PT == 0)
-    return Diag(LParenLoc, diag::err_typecheck_call_not_function,
-                Fn->getSourceRange());
-  const FunctionType *FuncT = PT->getPointeeType()->getAsFunctionType();
+  const FunctionType *FuncT;
+  if (!Fn->getType()->isBlockPointerType()) {
+    // C99 6.5.2.2p1 - "The expression that denotes the called function shall
+    // have type pointer to function".
+    const PointerType *PT = Fn->getType()->getAsPointerType();
+    if (PT == 0)
+      return Diag(LParenLoc, diag::err_typecheck_call_not_function,
+                  Fn->getSourceRange());
+    FuncT = PT->getPointeeType()->getAsFunctionType();
+  } else { // This is a block call.
+    FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
+                getAsFunctionType();
+  }
   if (FuncT == 0)
     return Diag(LParenLoc, diag::err_typecheck_call_not_function,
                 Fn->getSourceRange());
@@ -1012,7 +1051,10 @@
         NumArgsToCheck = NumArgsInProto;
         TheCall->setNumArgs(NumArgsInProto);
       } else
-        return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+        return Diag(RParenLoc, 
+                    !Fn->getType()->isBlockPointerType()
+                      ? diag::err_typecheck_call_too_few_args
+                      : diag::err_typecheck_block_too_few_args,
                     Fn->getSourceRange());
     }
 
@@ -1021,7 +1063,10 @@
     if (NumArgs > NumArgsInProto) {
       if (!Proto->isVariadic()) {
         Diag(Args[NumArgsInProto]->getLocStart(), 
-             diag::err_typecheck_call_too_many_args, Fn->getSourceRange(),
+               !Fn->getType()->isBlockPointerType()
+                 ? diag::err_typecheck_call_too_many_args
+                 : diag::err_typecheck_block_too_many_args, 
+             Fn->getSourceRange(),
              SourceRange(Args[NumArgsInProto]->getLocStart(),
                          Args[NumArgs-1]->getLocEnd()));
         // This deletes the extra arguments.
@@ -1529,8 +1574,8 @@
     if (isa<PointerType>(rhsType))
       return CheckPointerTypesForAssignment(lhsType, rhsType);
       
-    if (const BlockPointerType *BPT = rhsType->getAsBlockPointerType())
-      if (BPT->getPointeeType()->isVoidType())
+    if (rhsType->getAsBlockPointerType())
+      if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
         return BlockVoidPointer;
       
     return Incompatible;

Added: cfe/trunk/test/Sema/block-call.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-call.c?rev=55862&view=auto

==============================================================================
--- cfe/trunk/test/Sema/block-call.c (added)
+++ cfe/trunk/test/Sema/block-call.c Fri Sep  5 17:11:13 2008
@@ -0,0 +1,55 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int (*FP)();
+int (^IFP) ();
+int (^II) (int);
+int main() {
+  int (*FPL) (int) = FP; // C doesn't consider this an error.
+  
+  // For Blocks, the ASTContext::typesAreBlockCompatible() makes sure this is an error.
+	int (^PFR) (int) = IFP;	// expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int (^)(int)'}}
+	PFR = II;	// OK
+
+	int (^IFP) () = PFR;	// expected-error {{incompatible block pointer types initializing 'int (^)(int)', expected 'int (^)()'}}
+
+
+	const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
+
+
+	const int (^CICC) () = CIC;
+
+	int * const (^IPCC) () = 0;
+
+	int * const (^IPCC1) () = IPCC; 
+
+	int * (^IPCC2) () = IPCC;	// expected-error {{incompatible block pointer types initializing 'int *const (^)()', expected 'int *(^)()'}}
+
+	int (^IPCC3) (const int) = PFR;	// expected-error {{incompatible block pointer types initializing 'int (^)(int)', expected 'int (^)(int const)'}}
+
+
+	int (^IPCC4) (int, char (^CArg) (double));
+
+
+	int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
+
+	int (^IPCC6) (int, char (^CArg) (float))  = IPCC4; // expected-error {{incompatible block pointer types initializing 'int (^)(int, char (^)(double))', expected 'int (^)(int, char (^)(float))'}}
+
+	IPCC2 = 0;
+	IPCC2 = 1; // expected-error {{invalid conversion assigning integer 'int', expected block pointer 'int *(^)()'}}
+	int (^x)() = 0;
+	int (^y)() = 3;   // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+	int a = 1;
+	int (^z)() = a+4;   // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+}
+
+int blah() {
+	int (^IFP) (float);
+	char (^PCP)(double, double, char);
+
+	IFP(1.0);
+	IFP (1.0, 2.0);	// expected-error {{too many arguments to block call}}
+
+	char ch = PCP(1.0, 2.0, 'a');
+	return PCP(1.0, 2.0);	// expected-error {{too few arguments to block}}
+}
+

Added: cfe/trunk/test/Sema/block-misc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-misc.c?rev=55862&view=auto

==============================================================================
--- cfe/trunk/test/Sema/block-misc.c (added)
+++ cfe/trunk/test/Sema/block-misc.c Fri Sep  5 17:11:13 2008
@@ -0,0 +1,50 @@
+// RUN: clang -fsyntax-only -verify %s
+void donotwarn();
+
+int (^IFP) ();
+int (^II) (int);
+int test1() {
+	int (^PFR) (int) = 0;	// OK
+	PFR = II;	// OK
+
+	if (PFR == II)	// OK
+	  donotwarn();
+
+	if (PFR == IFP) // expected-error {{comparison of distinct block types}}
+	  donotwarn();
+
+	if (PFR == (int (^) (int))IFP) // OK
+	  donotwarn();
+
+	if (PFR == 0) // OK
+	  donotwarn();
+
+	if (PFR)	// OK
+	  donotwarn();
+
+	if (!PFR)	// OK
+	  donotwarn();
+
+	return PFR != IFP;	// expected-error {{comparison of distinct block types}}
+}
+
+int test2(double (^S)()) {
+   double (^I)(int)  = (void*) S;
+   (void*)I = (void *)S; 	// expected-error {{expression is not assignable}}
+
+   void *pv = I;
+
+   pv = S;		
+
+   I(1);
+ 
+   return (void*)I == (void *)S;
+}
+
+int^ x; // expected-error {{block pointer to non-function type is invalid}}
+int^^ x1; // expected-error {{block pointer to non-function type is invalid}}
+
+int test3() {
+	char *^ y; // expected-error {{block pointer to non-function type is invalid}}
+}
+





More information about the cfe-commits mailing list