From eab5f632076932ec1126413d419adc80978216ae Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Tue, 23 Sep 2008 19:24:41 +0000 Subject: [PATCH] Teach block rewriter to replace '^' with '*' in VarDecls. Since we don't have DeclGroup's and location information for types, there is some fancy footwork to do this fairly reliably. O.K...it's a kludge. One day, we can use this as motivation to do this more gracefully:-) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56499 91177308-0d34-0410-b5e6-96231b3b80d8 --- Driver/RewriteBlocks.cpp | 76 ++++++++++++++++++++++++++++++++------ test/Rewriter/block-test.c | 27 ++++++++++++++ 2 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 test/Rewriter/block-test.c diff --git a/Driver/RewriteBlocks.cpp b/Driver/RewriteBlocks.cpp index 4f91606bfa..b61e9a2241 100644 --- a/Driver/RewriteBlocks.cpp +++ b/Driver/RewriteBlocks.cpp @@ -131,6 +131,9 @@ public: void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl); void RewriteProtocolDecl(ObjCProtocolDecl *PDecl); void RewriteMethodDecl(ObjCMethodDecl *MDecl); + + bool BlockPointerTypeTakesAnyBlockArguments(QualType QT); + void GetExtentOfArgList(const char *Name, char *&LParen, char *&RParen); }; } @@ -455,9 +458,9 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i, } if (haveByRefDecls) { // Remove |...|. - const char *firstBarPtr = strchr(BodyStartBuf, '|'); - const char *secondBarPtr = strchr(firstBarPtr+1, '|'); - BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, ""); + //const char *firstBarPtr = strchr(BodyStartBuf, '|'); + //const char *secondBarPtr = strchr(firstBarPtr+1, '|'); + //BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, ""); } S += " "; S += BodyBuf; @@ -809,6 +812,40 @@ void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { return; } +bool RewriteBlocks::BlockPointerTypeTakesAnyBlockArguments(QualType QT) { + const BlockPointerType *BPT = QT->getAsBlockPointerType(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + const FunctionTypeProto *FTP = BPT->getPointeeType()->getAsFunctionTypeProto(); + if (FTP) { + for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) + if (isBlockPointerType(*I)) + return true; + } + return false; +} + +void RewriteBlocks::GetExtentOfArgList(const char *Name, + char *&LParen, char *&RParen) { + char *argPtr = strchr(Name, '('); + assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); + + LParen = argPtr; // output the start. + argPtr++; // skip past the left paren. + unsigned parenCount = 1; + + while (*argPtr && parenCount) { + switch (*argPtr) { + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; + } + if (parenCount) argPtr++; + } + assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); + RParen = argPtr; // output the end +} + void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { SourceLocation DeclLoc = ND->getLocation(); const char *startBuf, *endBuf; @@ -820,6 +857,29 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { DeclLoc = VD->getLocation(); startBuf = SM->getCharacterData(DeclLoc); endBuf = startBuf; + // scan backward (from the decl location) for the end of the previous decl. + while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) + startBuf--; + assert((*startBuf == '^') && + "RewriteBlockPointerDecl() scan error: no caret"); + // Replace the '^' with '*', computing a negative offset. + DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); + ReplaceText(DeclLoc, 1, "*", 1); + + if (BlockPointerTypeTakesAnyBlockArguments(VD->getType())) { + // Replace the '^' with '*' for arguments. + DeclLoc = VD->getLocation(); + startBuf = SM->getCharacterData(DeclLoc); + char *argListBegin, *argListEnd; + GetExtentOfArgList(startBuf, argListBegin, argListEnd); + while (argListBegin < argListEnd) { + if (*argListBegin == '^') { + SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); + ReplaceText(CaretLoc, 1, "*", 1); + } + argListBegin++; + } + } } else if (TypedefDecl *TDD = dyn_cast(ND)) { DeclLoc = TDD->getLocation(); startBuf = SM->getCharacterData(DeclLoc); @@ -828,15 +888,7 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { DeclLoc = DeclLoc.getFileLocWithOffset(8); } endBuf = startBuf; - } - // FIXME: need to skip past the argument list...then check for ','. - while (*endBuf && *endBuf != '=' && *endBuf != ';') - endBuf++; - - SourceLocation DeclEndLoc = DeclLoc.getFileLocWithOffset(endBuf-startBuf); - - std::string Tag = "struct __closure_impl *" + std::string(ND->getName()); - ReplaceText(DeclLoc, endBuf-startBuf, Tag.c_str(), Tag.size()); + } return; } diff --git a/test/Rewriter/block-test.c b/test/Rewriter/block-test.c new file mode 100644 index 0000000000..0a6bde0886 --- /dev/null +++ b/test/Rewriter/block-test.c @@ -0,0 +1,27 @@ +// RUN: clang -rewrite-blocks %s -o - + +typedef void (^test_block_t)(); + +int main(int argc, char **argv) { + int a; + + void (^test_block_v)(); + void (^test_block_v2)(int, float); + + void (^test_block_v3)(void (^barg)(int)); + + a = 77; + test_block_v = ^(){ int local=1; printf("a=%d\n",a+local); }; + test_block_v(); + a++; + test_block_v(); + + __block int b; + + b = 88; + test_block_v2 = ^(int x, float f){ printf("b=%d\n",b); }; + test_block_v2(1,2.0); + b++; + test_block_v2(3,4.0); + return 7; +}