]> granicus.if.org Git - clang/commitdiff
Patch to rewrite block pointers as arguments to
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 25 May 2010 15:56:08 +0000 (15:56 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 25 May 2010 15:56:08 +0000 (15:56 +0000)
methods. (Radar 7987817).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104608 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Frontend/RewriteObjC.cpp
test/Rewriter/rewrite-block-argument.m [new file with mode: 0644]

index 46883c99016c1f9d28a9ea2389aff9942242af99..606e5d546c2acce1ecde9c8306a64add73e88b37 100644 (file)
@@ -276,6 +276,7 @@ namespace {
     bool isSuperReceiver(Expr *recExpr);
     QualType getSuperStructType();
     QualType getConstantStringStructType();
+    QualType convertFunctionTypeOfBlocks(const FunctionType *FT);
     bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
 
     // Expression Rewriting.
@@ -2945,6 +2946,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
       QualType type = ICE->getType()->isObjCQualifiedIdType()
                                 ? Context->getObjCIdType()
                                 : ICE->getType();
+      // Make sure we convert "type (^)(...)" to "type (*)(...)".
+      if (isTopLevelBlockPointerType(type)) {
+        const BlockPointerType *BPT = type->getAs<BlockPointerType>();
+        type = Context->getPointerType(BPT->getPointeeType());
+      }
       userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown,
                                           userExpr);
     }
@@ -4113,7 +4119,14 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
          E = BD->param_end(); AI != E; ++AI) {
       if (AI != BD->param_begin()) S += ", ";
       ParamStr = (*AI)->getNameAsString();
-      (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
+      QualType QT = (*AI)->getType();
+      if (isTopLevelBlockPointerType(QT)) {
+        const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
+        Context->getPointerType(BPT->getPointeeType()).
+        getAsStringInternal(ParamStr, Context->PrintingPolicy);
+      }
+      else
+        QT.getAsStringInternal(ParamStr, Context->PrintingPolicy);      
       S += ParamStr;
     }
     if (FT->isVariadic()) {
@@ -4534,6 +4547,47 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
   return;
 }
 
+/// convertFunctionTypeOfBlocks - This routine converts a function type
+/// whose result type may be a block pointer or whose argument type(s)
+/// might be block pointers to an equivalent funtion type replacing
+/// all block pointers to function pointers.
+QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
+  const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+  // FTP will be null for closures that don't take arguments.
+  // Generate a funky cast.
+  llvm::SmallVector<QualType, 8> ArgTypes;
+  bool HasBlockType = false;
+  QualType Res = FT->getResultType();
+  if (isTopLevelBlockPointerType(Res)) {
+    const BlockPointerType *BPT = Res->getAs<BlockPointerType>();
+    Res = Context->getPointerType(BPT->getPointeeType());
+    HasBlockType = true;
+  }
+  
+  if (FTP) {
+    for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+         E = FTP->arg_type_end(); I && (I != E); ++I) {
+      QualType t = *I;
+      // Make sure we convert "t (^)(...)" to "t (*)(...)".
+      if (isTopLevelBlockPointerType(t)) {
+        const BlockPointerType *BPT = t->getAs<BlockPointerType>();
+        t = Context->getPointerType(BPT->getPointeeType());
+        HasBlockType = true;
+      }
+      ArgTypes.push_back(t);
+    }
+  }
+  QualType FuncType;
+  // FIXME. Does this work if block takes no argument but has a return type
+  // which is of block type?
+  if (HasBlockType)
+    FuncType = Context->getFunctionType(Res,
+                        &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0,
+                        false, false, 0, 0, FunctionType::ExtInfo());
+  else FuncType = QualType(FT, 0);
+  return FuncType;
+}
+
 Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
   // Navigate to relevant type information.
   const BlockPointerType *CPT = 0;
@@ -5176,7 +5230,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
   std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
 
   // Get a pointer to the function type so we can cast appropriately.
-  QualType FType = Context->getPointerType(QualType(Exp->getFunctionType(),0));
+  QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());
+  QualType FType = Context->getPointerType(BFT);
 
   FunctionDecl *FD;
   Expr *NewRep;
diff --git a/test/Rewriter/rewrite-block-argument.m b/test/Rewriter/rewrite-block-argument.m
new file mode 100644 (file)
index 0000000..4ebbef9
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp
+// radar 7987817
+
+void *sel_registerName(const char *);
+
+@interface Test {
+}
+@end
+
+@implementation Test
+
+- (void)enumerateProvidersWithBlock:(void (^)(void))block {
+    block();
+}
+
+- (void)providerEnumerator {
+    ^(void (^providerBlock)(void)) {
+        [self enumerateProvidersWithBlock:providerBlock];
+    };
+}
+
+- (void)testNilBlock {
+    [self enumerateProvidersWithBlock:0];
+}
+
+@end
+
+
+
+int main(int argc, char *argv[]) {
+    return 0;
+}