-rewrite-objc, C and blocks

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

-rewrite-objc, C and blocks

Pierre Habouzit
I intended to use clang -rewrite-objc to be able to compile code using
blocks on targets unsupported by clang. I'm totally uninterested in the
ObjC rewriting, only the blocks one.

Sadly, this rewriting module rewrites to C++ even when the source code
in question is just plain old C.

I'm under the impression, that when the source code is C, only the fact
that clang is generating structs with constructors and RAII use of the
defined blocks. For example:

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int a;
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };

    [...]

    int main(void) {
        int a = 1;
        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};

        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
        [...]
    }

I'm under the impression that the following "rewrite" would be correct:

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int a;
    #ifdef __cplusplus
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    #endif
    };
    #ifndef __cplusplus
    #define __main_block_impl_0(fp, desc, _a, flags) \
        ((struct __main_block_impl_0){               \
            .impl = {                                \
                .isa = &_NSConcreteStackBlock,       \
                .Flags = flags,                      \
                .FuncPtr = fp,                       \
            },                                       \
            .Desc = desc,                            \
            .a = (_a),                               \
        })
    #endif

    [...]

    int main(void) {
        int a = 1;
        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};

        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
        [...]
    }


Am I correct, or am I missing something obvious ?


--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

Pierre Habouzit
If my assumptions are correct, attached is a patch that implements that.

--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org

>From a635ee053b59c5ad0617f227422295370da6dc1e Mon Sep 17 00:00:00 2001
From: Pierre Habouzit <[hidden email]>
Date: Fri, 1 Oct 2010 13:12:02 +0200
Subject: [PATCH] Try to make -rewrite-objc result buildable by a C compiler.

If the source is plain C, then, only blocks extensions can appear (no
objective C constructs). Hence it's a bit sad to generate C++ code just
for blocks when plain C code would just work fine.

Generate a compile-time selected code to either use structs constructors
(when the compiler supports c++) or macro-based C99 initializers when the
compiler is a C one.

Also, add a missing forward declaration of objc_super.

Signed-off-by: Pierre Habouzit <[hidden email]>
---
 lib/Rewrite/RewriteObjC.cpp |   81 +++++++++++++++++++++++++++++--------------
 1 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index dd6cf93..a099ff1 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -547,7 +547,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
   // scope related warning...
   if (IsHeader)
     Preamble = "#pragma once\n";
-  Preamble += "struct objc_selector; struct objc_class;\n";
+  Preamble += "struct objc_selector; struct objc_class; struct objc_super;\n";
   Preamble += "struct __rw_objc_super { struct objc_object *object; ";
   Preamble += "struct objc_object *superClass; ";
   if (LangOpts.Microsoft) {
@@ -4188,6 +4188,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
                                              std::string Desc) {
   std::string S = "\nstruct " + Tag;
   std::string Constructor = "  " + Tag;
+  std::string cConstructor = "#define " + Tag;
 
   S += " {\n  struct __block_impl impl;\n";
   S += "  struct " + Desc;
@@ -4196,6 +4197,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
   Constructor += "(void *fp, "; // Invoke function pointer.
   Constructor += "struct " + Desc; // Descriptor pointer.
   Constructor += " *desc";
+  cConstructor += "(fp, desc";
 
   if (BlockDeclRefs.size()) {
     // Output all "by copy" declarations.
@@ -4214,6 +4216,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       //     myImportedBlock(); // import and invoke the closure
       //   };
       //
+      cConstructor += ", " + ArgName;
       if (isTopLevelBlockPointerType((*I)->getType())) {
         S += "struct __block_impl *";
         Constructor += ", void *" + ArgName;
@@ -4243,6 +4246,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       //     myImportedBlock(); // import and invoke the closure
       //   };
       //
+      cConstructor += ", " + ArgName;
       if (isTopLevelBlockPointerType((*I)->getType())) {
         S += "struct __block_impl *";
         Constructor += ", void *" + ArgName;
@@ -4258,6 +4262,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
     }
     // Finish writing the constructor.
     Constructor += ", int flags=0)";
+    cConstructor += ", flags) \\\n";
+    cConstructor += "  ((struct " + Tag + "){ \\\n";
     // Initialize all "by copy" arguments.
     bool firsTime = true;
     for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
@@ -4269,10 +4275,14 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
         }
         else
           Constructor += ", ";
-        if (isTopLevelBlockPointerType((*I)->getType()))
+        cConstructor += "    ." + Name + " = ";
+        if (isTopLevelBlockPointerType((*I)->getType())) {
           Constructor += Name + "((struct __block_impl *)_" + Name + ")";
-        else
+          cConstructor += "((struct __block_impl *)(_" + Name + ")), \\\n";
+        } else {
           Constructor += Name + "(_" + Name + ")";
+          cConstructor += "(_" + Name + "), \\\n";
+        }
     }
     // Initialize all "by ref" arguments.
     for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
@@ -4284,35 +4294,51 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       }
       else
         Constructor += ", ";
-      if (isTopLevelBlockPointerType((*I)->getType()))
+      cConstructor += "    ." + Name + " = ";
+      if (isTopLevelBlockPointerType((*I)->getType())) {
         Constructor += Name + "((struct __block_impl *)_"
-                        + Name + "->__forwarding)";
-      else
+                        + Name + "->__forwarding), \\\n";
+        cConstructor += "((struct __block_impl *)(_" + Name + ")->__forwarding)";
+      } else {
         Constructor += Name + "(_" + Name + "->__forwarding)";
+        cConstructor += "((_" + Name + ")->__forwarding), \\\n";
+      }
     }
-    
-    Constructor += " {\n";
-    if (GlobalVarDecl)
-      Constructor += "    impl.isa = &_NSConcreteGlobalBlock;\n";
-    else
-      Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
-    Constructor += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
 
-    Constructor += "    Desc = desc;\n";
+    Constructor += " {\n";
   } else {
     // Finish writing the constructor.
     Constructor += ", int flags=0) {\n";
-    if (GlobalVarDecl)
-      Constructor += "    impl.isa = &_NSConcreteGlobalBlock;\n";
-    else
-      Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
-    Constructor += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
-    Constructor += "    Desc = desc;\n";
+    cConstructor += ", flags) \\\n";
+    cConstructor += "  ((struct " + Tag + "){ \\\n";
+  }
+
+  cConstructor += "    .impl = { \\\n";
+  if (GlobalVarDecl) {
+    Constructor  += "    impl.isa = &_NSConcreteGlobalBlock;\n";
+    cConstructor += "      .isa = &_NSConcreteGlobalBlock, \\\n";
+  } else {
+    Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
+    cConstructor += "      .isa = &_NSConcreteStackBlock, \\\n";
   }
+  Constructor  += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
+  Constructor += "    Desc = desc;\n";
   Constructor += "  ";
   Constructor += "}\n";
+  cConstructor +=
+    "      .Flags = (flags), \\\n"
+    "      .FuncPtr = (fp), \\\n"
+    "    }, \\\n"
+    "    .Desc = (desc), \\\n"
+    "  })\n";
+
+  S += "#ifdef __cplusplus\n";
   S += Constructor;
+  S += "#endif\n";
   S += "};\n";
+  S += "#ifndef __cplusplus\n";
+  S += cConstructor;
+  S += "#endif\n";
   return S;
 }
 
@@ -5271,15 +5297,18 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
       InitExprs.push_back(Exp);
     }
   }
+
+  int flag = 0;
   if (ImportedBlockDecls.size()) {
     // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
-    int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
-    unsigned IntSize =
-      static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
-    Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
-                                           Context->IntTy, SourceLocation());
-    InitExprs.push_back(FlagExp);
+    flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
   }
+  unsigned IntSize =
+    static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+  Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
+                                         Context->IntTy, SourceLocation());
+  InitExprs.push_back(FlagExp);
+
   NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
                                   FType, SourceLocation());
   NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
--
1.7.2.2.566.g36af9


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

jahanian
In reply to this post by Pierre Habouzit
Concept is right. However, rewriter project was done for a specific purpose and generates c++ code
as the input might be objective-c++. It is best for you to use the rewrite-obj model and have you own
-rewrite-block which generates c code.

- Fariborz

On Oct 1, 2010, at 3:16 AM, Pierre Habouzit wrote:

> I intended to use clang -rewrite-objc to be able to compile code using
> blocks on targets unsupported by clang. I'm totally uninterested in the
> ObjC rewriting, only the blocks one.
>
> Sadly, this rewriting module rewrites to C++ even when the source code
> in question is just plain old C.
>
> I'm under the impression, that when the source code is C, only the fact
> that clang is generating structs with constructors and RAII use of the
> defined blocks. For example:
>
>    struct __main_block_impl_0 {
>      struct __block_impl impl;
>      struct __main_block_desc_0* Desc;
>      int a;
>      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
>        impl.isa = &_NSConcreteStackBlock;
>        impl.Flags = flags;
>        impl.FuncPtr = fp;
>        Desc = desc;
>      }
>    };
>
>    [...]
>
>    int main(void) {
>        int a = 1;
>        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
>
>        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
>        [...]
>    }
>
> I'm under the impression that the following "rewrite" would be correct:
>
>    struct __main_block_impl_0 {
>      struct __block_impl impl;
>      struct __main_block_desc_0* Desc;
>      int a;
>    #ifdef __cplusplus
>      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
>        impl.isa = &_NSConcreteStackBlock;
>        impl.Flags = flags;
>        impl.FuncPtr = fp;
>        Desc = desc;
>      }
>    #endif
>    };
>    #ifndef __cplusplus
>    #define __main_block_impl_0(fp, desc, _a, flags) \
>        ((struct __main_block_impl_0){               \
>            .impl = {                                \
>                .isa = &_NSConcreteStackBlock,       \
>                .Flags = flags,                      \
>                .FuncPtr = fp,                       \
>            },                                       \
>            .Desc = desc,                            \
>            .a = (_a),                               \
>        })
>    #endif
>
>    [...]
>
>    int main(void) {
>        int a = 1;
>        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
>
>        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
>        [...]
>    }
>
>
> Am I correct, or am I missing something obvious ?
>
>
> --
> ·O·  Pierre Habouzit
> ··O                                                [hidden email]
> OOO                                                http://www.madism.org
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

Pierre Habouzit
Well, there used to be a -rewrite-blocks and there is a commmit that
says that it's superseeded by -rewrite-objc.

Plus what my patch does is that if it's a c++ compiler that is used,
then the c++ code is used, else it tries to be c-compatible.

So would a pure C-to-C blocks rewriter (reintroducing -rewrite-blocks)
be accepted ? I'd like to avoid maintaining a custom patch forever :)

On Fri, Oct 01, 2010 at 09:00:57AM -0700, jahanian wrote:

> Concept is right. However, rewriter project was done for a specific purpose and generates c++ code
> as the input might be objective-c++. It is best for you to use the rewrite-obj model and have you own
> -rewrite-block which generates c code.
>
> - Fariborz
>
> On Oct 1, 2010, at 3:16 AM, Pierre Habouzit wrote:
>
> > I intended to use clang -rewrite-objc to be able to compile code using
> > blocks on targets unsupported by clang. I'm totally uninterested in the
> > ObjC rewriting, only the blocks one.
> >
> > Sadly, this rewriting module rewrites to C++ even when the source code
> > in question is just plain old C.
> >
> > I'm under the impression, that when the source code is C, only the fact
> > that clang is generating structs with constructors and RAII use of the
> > defined blocks. For example:
> >
> >    struct __main_block_impl_0 {
> >      struct __block_impl impl;
> >      struct __main_block_desc_0* Desc;
> >      int a;
> >      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
> >        impl.isa = &_NSConcreteStackBlock;
> >        impl.Flags = flags;
> >        impl.FuncPtr = fp;
> >        Desc = desc;
> >      }
> >    };
> >
> >    [...]
> >
> >    int main(void) {
> >        int a = 1;
> >        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
> >
> >        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
> >        [...]
> >    }
> >
> > I'm under the impression that the following "rewrite" would be correct:
> >
> >    struct __main_block_impl_0 {
> >      struct __block_impl impl;
> >      struct __main_block_desc_0* Desc;
> >      int a;
> >    #ifdef __cplusplus
> >      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
> >        impl.isa = &_NSConcreteStackBlock;
> >        impl.Flags = flags;
> >        impl.FuncPtr = fp;
> >        Desc = desc;
> >      }
> >    #endif
> >    };
> >    #ifndef __cplusplus
> >    #define __main_block_impl_0(fp, desc, _a, flags) \
> >        ((struct __main_block_impl_0){               \
> >            .impl = {                                \
> >                .isa = &_NSConcreteStackBlock,       \
> >                .Flags = flags,                      \
> >                .FuncPtr = fp,                       \
> >            },                                       \
> >            .Desc = desc,                            \
> >            .a = (_a),                               \
> >        })
> >    #endif
> >
> >    [...]
> >
> >    int main(void) {
> >        int a = 1;
> >        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
> >
> >        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
> >        [...]
> >    }
> >
> >
> > Am I correct, or am I missing something obvious ?
> >
> >
> > --
> > ·O·  Pierre Habouzit
> > ··O                                                [hidden email]
> > OOO                                                http://www.madism.org
> > _______________________________________________
> > cfe-dev mailing list
> > [hidden email]
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>

--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

Pierre Habouzit
Also, is obj-c++ defining __cplusplus ? if yes, then my proposal works
with obj-c++ just fine

On Fri, Oct 01, 2010 at 07:54:57PM +0200, Pierre Habouzit wrote:

> Well, there used to be a -rewrite-blocks and there is a commmit that
> says that it's superseeded by -rewrite-objc.
>
> Plus what my patch does is that if it's a c++ compiler that is used,
> then the c++ code is used, else it tries to be c-compatible.
>
> So would a pure C-to-C blocks rewriter (reintroducing -rewrite-blocks)
> be accepted ? I'd like to avoid maintaining a custom patch forever :)
>
> On Fri, Oct 01, 2010 at 09:00:57AM -0700, jahanian wrote:
> > Concept is right. However, rewriter project was done for a specific purpose and generates c++ code
> > as the input might be objective-c++. It is best for you to use the rewrite-obj model and have you own
> > -rewrite-block which generates c code.
> >
> > - Fariborz
> >
> > On Oct 1, 2010, at 3:16 AM, Pierre Habouzit wrote:
> >
> > > I intended to use clang -rewrite-objc to be able to compile code using
> > > blocks on targets unsupported by clang. I'm totally uninterested in the
> > > ObjC rewriting, only the blocks one.
> > >
> > > Sadly, this rewriting module rewrites to C++ even when the source code
> > > in question is just plain old C.
> > >
> > > I'm under the impression, that when the source code is C, only the fact
> > > that clang is generating structs with constructors and RAII use of the
> > > defined blocks. For example:
> > >
> > >    struct __main_block_impl_0 {
> > >      struct __block_impl impl;
> > >      struct __main_block_desc_0* Desc;
> > >      int a;
> > >      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
> > >        impl.isa = &_NSConcreteStackBlock;
> > >        impl.Flags = flags;
> > >        impl.FuncPtr = fp;
> > >        Desc = desc;
> > >      }
> > >    };
> > >
> > >    [...]
> > >
> > >    int main(void) {
> > >        int a = 1;
> > >        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
> > >
> > >        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
> > >        [...]
> > >    }
> > >
> > > I'm under the impression that the following "rewrite" would be correct:
> > >
> > >    struct __main_block_impl_0 {
> > >      struct __block_impl impl;
> > >      struct __main_block_desc_0* Desc;
> > >      int a;
> > >    #ifdef __cplusplus
> > >      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
> > >        impl.isa = &_NSConcreteStackBlock;
> > >        impl.Flags = flags;
> > >        impl.FuncPtr = fp;
> > >        Desc = desc;
> > >      }
> > >    #endif
> > >    };
> > >    #ifndef __cplusplus
> > >    #define __main_block_impl_0(fp, desc, _a, flags) \
> > >        ((struct __main_block_impl_0){               \
> > >            .impl = {                                \
> > >                .isa = &_NSConcreteStackBlock,       \
> > >                .Flags = flags,                      \
> > >                .FuncPtr = fp,                       \
> > >            },                                       \
> > >            .Desc = desc,                            \
> > >            .a = (_a),                               \
> > >        })
> > >    #endif
> > >
> > >    [...]
> > >
> > >    int main(void) {
> > >        int a = 1;
> > >        struct __Block_byref_c_0 c = {(void*)0,(struct __Block_byref_c_0 *)&c, 0, sizeof(struct __Block_byref_c_0), 1};
> > >
> > >        int (*f)(int) = (int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a);
> > >        [...]
> > >    }
> > >
> > >
> > > Am I correct, or am I missing something obvious ?
> > >
> > >
> > > --
> > > ·O·  Pierre Habouzit
> > > ··O                                                [hidden email]
> > > OOO                                                http://www.madism.org
> > > _______________________________________________
> > > cfe-dev mailing list
> > > [hidden email]
> > > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
> >
>
> --
> ·O·  Pierre Habouzit
> ··O                                                [hidden email]
> OOO                                                http://www.madism.org

--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

-rewrite-objc and typeof (Was: -rewrite-objc, C and blocks)

Pierre Habouzit
In reply to this post by Pierre Habouzit

While I'm at it, the objc rewriter tries hard to rewrite typeof() for a
reason that eludes me.  Given that typeof() is often used inside macros,
and that rewriting inside macros may not work (that I can understand
;p), this is really painful.

So could someone explain why the RewriteObjC::RewriteTypeOfDecl()
function is needed at all so that I can work on a fix or at least a
relaxed rule (for example, I assume that the problem arises if the
type of the expression inside typeof really is some block type or some
variable with a __block storage ? or something block related at least,
so probably the fix is to check if the type is something of that kind,
right ?)

The use case is code using stuff like:

    #define shared_write(p, v)  ({ typeof(v) __v = (v); \
                                   access_once(p) = __v; wmc(); __v; })

clang -rewrite-objc yields tons of warnings like:

    thr-job.c:198:5: warning: rewriting sub-expression within a macro (may not be correct)
        shared_write(self_g.bot_, new_bot);
        ^
    [...]
    ../lib-common/core-atomic-x86.h:80:32: note: instantiated from:
    #define shared_write(p, v)  ({ typeof(v) __v = (v); \
                                   ^

Given that in the previous code self_g.bot is an unsigned, I really fail
to see why clang believes it has to rewrite the typeof() expression at
all.
--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

jahanian
In reply to this post by Pierre Habouzit

On Oct 1, 2010, at 10:54 AM, Pierre Habouzit wrote:

> Well, there used to be a -rewrite-blocks and there is a commmit that
> says that it's superseeded by -rewrite-objc.
>
> Plus what my patch does is that if it's a c++ compiler that is used,
> then the c++ code is used, else it tries to be c-compatible.
>
> So would a pure C-to-C blocks rewriter (reintroducing -rewrite-blocks)
> be accepted ? I'd like to avoid maintaining a custom patch forever :)

I think so. This always prototyping of blocks for other platforms without the baggage
associated with objective-c (or c++).

- Fariborz

>


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc, C and blocks

jahanian
In reply to this post by Pierre Habouzit

On Oct 1, 2010, at 10:56 AM, Pierre Habouzit wrote:

> Also, is obj-c++ defining __cplusplus ? if yes, then my proposal works
> with obj-c++ just fine

objective-c++ is a super-set of c++. So __cplusplus is defined.

- fariborz.

>

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc and typeof (Was: -rewrite-objc, C and blocks)

jahanian
In reply to this post by Pierre Habouzit

On Oct 1, 2010, at 1:42 PM, Pierre Habouzit wrote:

>
> While I'm at it, the objc rewriter tries hard to rewrite typeof() for a
> reason that eludes me.  Given that typeof() is often used inside macros,
> and that rewriting inside macros may not work (that I can understand
> ;p), this is really painful.

We needed to support rewriting of __typeof because of our requirements.
There is a test case under Rewrite/rewrite-typeof.mm which specifically
tests this.
This is one other reason to have a separate rewriter  without baggage associated
with our specific needs.

- Fariborz

>
> So could someone explain why the RewriteObjC::RewriteTypeOfDecl()
> function is needed at all so that I can work on a fix or at least a
> relaxed rule (for example, I assume that the problem arises if the
> type of the expression inside typeof really is some block type or some
> variable with a __block storage ? or something block related at least,
> so probably the fix is to check if the type is something of that kind,
> right ?)
>
> The use case is code using stuff like:
>
>    #define shared_write(p, v)  ({ typeof(v) __v = (v); \
>   access_once(p) = __v; wmc(); __v; })
>
> clang -rewrite-objc yields tons of warnings like:
>
>    thr-job.c:198:5: warning: rewriting sub-expression within a macro (may not be correct)
> shared_write(self_g.bot_, new_bot);
> ^
>    [...]
>    ../lib-common/core-atomic-x86.h:80:32: note: instantiated from:
>    #define shared_write(p, v)  ({ typeof(v) __v = (v); \
>   ^
>
> Given that in the previous code self_g.bot is an unsigned, I really fail
> to see why clang believes it has to rewrite the typeof() expression at
> all.
> --
> ·O·  Pierre Habouzit
> ··O                                                [hidden email]
> OOO                                                http://www.madism.org
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc and typeof (Was: -rewrite-objc, C and blocks)

Pierre Habouzit
On Fri, Oct 01, 2010 at 02:14:09PM -0700, jahanian wrote:

>
> On Oct 1, 2010, at 1:42 PM, Pierre Habouzit wrote:
>
> >
> > While I'm at it, the objc rewriter tries hard to rewrite typeof() for a
> > reason that eludes me.  Given that typeof() is often used inside macros,
> > and that rewriting inside macros may not work (that I can understand
> > ;p), this is really painful.
>
> We needed to support rewriting of __typeof because of our requirements.
> There is a test case under Rewrite/rewrite-typeof.mm which specifically
> tests this.

To be frank it still doesn't explain why you need it at all, but fine :)

> This is one other reason to have a separate rewriter  without baggage
> associated with our specific needs.

Well, I've made the work of taking the block rewriting code from
RewriteObjC.cpp, it's huge, and I'm uncomfortable duplicating that
amount of code.

So what is the best approach, is it writing a new RewriteBlocks class
that RewriteObjC would inherit from (but it's a very huge work) or
simply make RewriteObjC have a "bool RewriteBlocksOnly" setting that is
selected whether it's called from -rewrite-objc or -rewrite-blocks on
the command line, and that would affect how code is generated ?

I'd rather go for the latter that is simpler, as mostly for now, it will
just disable the typeof rewriting, simplify the preamble (the objc stuff
isn't required), and keep my previous patch so that the generated code
still works when compiled with a c++ compiler.

Would that be acceptable ?
--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc and typeof (Was: -rewrite-objc, C and blocks)

Pierre Habouzit
On Sat, Oct 02, 2010 at 09:19:11AM +0200, Pierre Habouzit wrote:

> On Fri, Oct 01, 2010 at 02:14:09PM -0700, jahanian wrote:
> >
> > On Oct 1, 2010, at 1:42 PM, Pierre Habouzit wrote:
> >
> > >
> > > While I'm at it, the objc rewriter tries hard to rewrite typeof() for a
> > > reason that eludes me.  Given that typeof() is often used inside macros,
> > > and that rewriting inside macros may not work (that I can understand
> > > ;p), this is really painful.
> >
> > We needed to support rewriting of __typeof because of our requirements.
> > There is a test case under Rewrite/rewrite-typeof.mm which specifically
> > tests this.
>
> To be frank it still doesn't explain why you need it at all, but fine :)
>
> > This is one other reason to have a separate rewriter  without baggage
> > associated with our specific needs.
>
> Well, I've made the work of taking the block rewriting code from
> RewriteObjC.cpp, it's huge, and I'm uncomfortable duplicating that
> amount of code.
>
> So what is the best approach, is it writing a new RewriteBlocks class
> that RewriteObjC would inherit from (but it's a very huge work) or
> simply make RewriteObjC have a "bool RewriteBlocksOnly" setting that is
> selected whether it's called from -rewrite-objc or -rewrite-blocks on
> the command line, and that would affect how code is generated ?
>
> I'd rather go for the latter that is simpler, as mostly for now, it will
> just disable the typeof rewriting, simplify the preamble (the objc stuff
> isn't required), and keep my previous patch so that the generated code
> still works when compiled with a c++ compiler.
>
> Would that be acceptable ?
For example, it could be the two attached patches, the first one being a
rework of my previous patch to simplify a few things, and the second
(re)introducing -rewrite-blocks using the ObjCRewriter with the ObjC
rewriting actually disabled.

I've sent a version of the patch where blank changes are ignored for the
second one for those who want to understand the actual changes it does.
--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org

>From b86eba14503056057c362f51315e8dcf809d347f Mon Sep 17 00:00:00 2001
From: Pierre Habouzit <[hidden email]>
Date: Fri, 1 Oct 2010 13:12:02 +0200
Subject: [PATCH 1/2] Try to make -rewrite-objc result buildable by a C compiler.

If the source is plain C, then, only blocks extensions can appear (no
objective C constructs). Hence it's a bit sad to generate C++ code just
for blocks when plain C code would just work fine.

Generate a compile-time selected code to either use structs constructors
(when the compiler supports c++) or macro-based C99 initializers when the
compiler is a C one.

Also, add a missing forward declaration of objc_super.

Signed-off-by: Pierre Habouzit <[hidden email]>
---
 lib/Rewrite/RewriteObjC.cpp |   80 +++++++++++++++++++++++++++++--------------
 1 files changed, 54 insertions(+), 26 deletions(-)

diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index dd6cf93..dfea0c9 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -547,7 +547,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
   // scope related warning...
   if (IsHeader)
     Preamble = "#pragma once\n";
-  Preamble += "struct objc_selector; struct objc_class;\n";
+  Preamble += "struct objc_selector; struct objc_class; struct objc_super;\n";
   Preamble += "struct __rw_objc_super { struct objc_object *object; ";
   Preamble += "struct objc_object *superClass; ";
   if (LangOpts.Microsoft) {
@@ -4188,6 +4188,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
                                              std::string Desc) {
   std::string S = "\nstruct " + Tag;
   std::string Constructor = "  " + Tag;
+  std::string cConstructor = "#define " + Tag;
 
   S += " {\n  struct __block_impl impl;\n";
   S += "  struct " + Desc;
@@ -4196,6 +4197,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
   Constructor += "(void *fp, "; // Invoke function pointer.
   Constructor += "struct " + Desc; // Descriptor pointer.
   Constructor += " *desc";
+  cConstructor += "(fp, desc";
 
   if (BlockDeclRefs.size()) {
     // Output all "by copy" declarations.
@@ -4214,6 +4216,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       //     myImportedBlock(); // import and invoke the closure
       //   };
       //
+      cConstructor += ", " + ArgName;
       if (isTopLevelBlockPointerType((*I)->getType())) {
         S += "struct __block_impl *";
         Constructor += ", void *" + ArgName;
@@ -4243,6 +4246,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       //     myImportedBlock(); // import and invoke the closure
       //   };
       //
+      cConstructor += ", " + ArgName;
       if (isTopLevelBlockPointerType((*I)->getType())) {
         S += "struct __block_impl *";
         Constructor += ", void *" + ArgName;
@@ -4258,6 +4262,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
     }
     // Finish writing the constructor.
     Constructor += ", int flags=0)";
+    cConstructor += ", flags) \\\n";
+    cConstructor += "  ((struct " + Tag + "){ \\\n";
     // Initialize all "by copy" arguments.
     bool firsTime = true;
     for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
@@ -4269,10 +4275,14 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
         }
         else
           Constructor += ", ";
-        if (isTopLevelBlockPointerType((*I)->getType()))
+        cConstructor += "    ." + Name + " = ";
+        if (isTopLevelBlockPointerType((*I)->getType())) {
           Constructor += Name + "((struct __block_impl *)_" + Name + ")";
-        else
+          cConstructor += "((struct __block_impl *)(_" + Name + ")), \\\n";
+        } else {
           Constructor += Name + "(_" + Name + ")";
+          cConstructor += "(_" + Name + "), \\\n";
+        }
     }
     // Initialize all "by ref" arguments.
     for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
@@ -4284,34 +4294,49 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
       }
       else
         Constructor += ", ";
-      if (isTopLevelBlockPointerType((*I)->getType()))
+      cConstructor += "    ." + Name + " = ";
+      if (isTopLevelBlockPointerType((*I)->getType())) {
         Constructor += Name + "((struct __block_impl *)_"
-                        + Name + "->__forwarding)";
-      else
+                        + Name + "->__forwarding), \\\n";
+        cConstructor += "((struct __block_impl *)(_" + Name + ")->__forwarding)";
+      } else {
         Constructor += Name + "(_" + Name + "->__forwarding)";
+        cConstructor += "((_" + Name + ")->__forwarding), \\\n";
+      }
     }
-    
-    Constructor += " {\n";
-    if (GlobalVarDecl)
-      Constructor += "    impl.isa = &_NSConcreteGlobalBlock;\n";
-    else
-      Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
-    Constructor += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
 
-    Constructor += "    Desc = desc;\n";
+    Constructor += " {\n";
   } else {
     // Finish writing the constructor.
     Constructor += ", int flags=0) {\n";
-    if (GlobalVarDecl)
-      Constructor += "    impl.isa = &_NSConcreteGlobalBlock;\n";
-    else
-      Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
-    Constructor += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
-    Constructor += "    Desc = desc;\n";
+    cConstructor += ", flags) \\\n";
+    cConstructor += "  ((struct " + Tag + "){ \\\n";
+  }
+
+  cConstructor += "    .impl = { \\\n";
+  if (GlobalVarDecl) {
+    Constructor  += "    impl.isa = &_NSConcreteGlobalBlock;\n";
+    cConstructor += "      .isa = &_NSConcreteGlobalBlock, \\\n";
+  } else {
+    Constructor += "    impl.isa = &_NSConcreteStackBlock;\n";
+    cConstructor += "      .isa = &_NSConcreteStackBlock, \\\n";
   }
+  Constructor  += "    impl.Flags = flags;\n    impl.FuncPtr = fp;\n";
+  Constructor += "    Desc = desc;\n";
   Constructor += "  ";
   Constructor += "}\n";
+  cConstructor +=
+    "      .Flags = (flags), \\\n"
+    "      .FuncPtr = (fp), \\\n"
+    "    }, \\\n"
+    "    .Desc = (desc), \\\n"
+    "  })\n";
+
+  S += "#ifdef __cplusplus\n";
   S += Constructor;
+  S += "#else\n";
+  S += cConstructor;
+  S += "#endif\n";
   S += "};\n";
   return S;
 }
@@ -5271,15 +5296,18 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
       InitExprs.push_back(Exp);
     }
   }
+
+  int flag = 0;
   if (ImportedBlockDecls.size()) {
     // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
-    int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
-    unsigned IntSize =
-      static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
-    Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
-                                           Context->IntTy, SourceLocation());
-    InitExprs.push_back(FlagExp);
+    flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
   }
+  unsigned IntSize =
+    static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+  Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
+                                         Context->IntTy, SourceLocation());
+  InitExprs.push_back(FlagExp);
+
   NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
                                   FType, SourceLocation());
   NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
--
1.7.2.2.566.g36af9


>From 9663cf81240ff891ad292f576f789302f0582dd9 Mon Sep 17 00:00:00 2001
From: Pierre Habouzit <[hidden email]>
Date: Sat, 2 Oct 2010 09:47:35 +0200
Subject: [PATCH 2/2] Introduce -rewrite-blocks

Make it use a subset of the ObjC Rewriter.

For now it basically does two things:
- for one it tries to keep the language the code is written in, whether it
  is C, C++, ObjC or ObjC++, using RAII when the language is C++-based
- it disables typeof and objc rewriting

Signed-off-by: Pierre Habouzit <[hidden email]>
---
 include/clang/Driver/CC1Options.td             |    2 +
 include/clang/Frontend/FrontendOptions.h       |    1 +
 include/clang/Rewrite/ASTConsumers.h           |    7 +
 include/clang/Rewrite/FrontendActions.h        |    6 +
 lib/Frontend/CompilerInvocation.cpp            |    3 +
 lib/FrontendTool/ExecuteCompilerInvocation.cpp |    1 +
 lib/Rewrite/FrontendActions.cpp                |   12 +
 lib/Rewrite/RewriteObjC.cpp                    |  275 +++++++++++++-----------
 8 files changed, 184 insertions(+), 123 deletions(-)

diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 512c2ca..7881972 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -351,6 +351,8 @@ def rewrite_test : Flag<"-rewrite-test">,
   HelpText<"Rewriter playground">;
 def rewrite_objc : Flag<"-rewrite-objc">,
   HelpText<"Rewrite ObjC into C (code rewriter example)">;
+def rewrite_blocks : Flag<"-rewrite-blocks">,
+  HelpText<"Rewrite C with blocks source to plain C99">;
 def rewrite_macros : Flag<"-rewrite-macros">,
   HelpText<"Expand macros without full preprocessing">;
 
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 4c16d08..2cbe940 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -46,6 +46,7 @@ namespace frontend {
     PrintPreamble,          ///< Print the "preamble" of the input file
     PrintPreprocessedInput, ///< -E mode.
     RewriteMacros,          ///< Expand macros but not #includes.
+    RewriteBlocks,          ///< C+Blocks -> C Rewriter
     RewriteObjC,            ///< ObjC->C Rewriter.
     RewriteTest,            ///< Rewriter playground
     RunAnalysis,            ///< Run one or more source code analyses.
diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/ASTConsumers.h
index 5fb107c..9ef7baa 100644
--- a/include/clang/Rewrite/ASTConsumers.h
+++ b/include/clang/Rewrite/ASTConsumers.h
@@ -34,6 +34,13 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile,
                                 const LangOptions &LOpts,
                                 bool SilenceRewriteMacroWarning);
 
+// Blocks rewriter: attempts to rewrite Blocks constructs into pure C code.
+ASTConsumer *CreateBlocksRewriter(const std::string &InFile,
+                                  llvm::raw_ostream *OS,
+                                  Diagnostic &Diags,
+                                  const LangOptions &LOpts,
+                                  bool SilenceRewriteMacroWarning);
+
 /// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
 /// HTML with syntax highlighting suitable for viewing in a web-browser.
 ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP,
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 2b5f88c..bd0c4f4 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -54,6 +54,12 @@ protected:
                                          llvm::StringRef InFile);
 };
 
+class RewriteBlocksAction : public ASTFrontendAction {
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile);
+};
+
 class RewriteMacrosAction : public PreprocessorFrontendAction {
 protected:
   void ExecuteAction();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d793fc0..1a64600 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -343,6 +343,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
   case frontend::PrintPreamble:          return "-print-preamble";
   case frontend::PrintPreprocessedInput: return "-E";
   case frontend::RewriteMacros:          return "-rewrite-macros";
+  case frontend::RewriteBlocks:          return "-rewrite-blocks";
   case frontend::RewriteObjC:            return "-rewrite-objc";
   case frontend::RewriteTest:            return "-rewrite-test";
   case frontend::RunAnalysis:            return "-analyze";
@@ -1035,6 +1036,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
       Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
     case OPT_rewrite_macros:
       Opts.ProgramAction = frontend::RewriteMacros; break;
+    case OPT_rewrite_blocks:
+      Opts.ProgramAction = frontend::RewriteBlocks; break;
     case OPT_rewrite_objc:
       Opts.ProgramAction = frontend::RewriteObjC; break;
     case OPT_rewrite_test:
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 63c6287..fe362d8 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -77,6 +77,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   case PrintPreamble:          return new PrintPreambleAction();
   case PrintPreprocessedInput: return new PrintPreprocessedAction();
   case RewriteMacros:          return new RewriteMacrosAction();
+  case RewriteBlocks:          return new RewriteBlocksAction();
   case RewriteObjC:            return new RewriteObjCAction();
   case RewriteTest:            return new RewriteTestAction();
   case RunAnalysis:            return new AnalysisAction();
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index 977e0cf..3f5cac7 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -98,6 +98,18 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
   return 0;
 }
 
+ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
+                                                    llvm::StringRef InFile) {
+  llvm::sys::Path Path(InFile);
+  llvm::Twine suffix("rw." + Path.getSuffix());
+
+  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, suffix.str()))
+    return CreateBlocksRewriter(InFile, OS,
+                                CI.getDiagnostics(), CI.getLangOpts(),
+                                CI.getDiagnosticOpts().NoRewriteMacros);
+  return 0;
+}
+
 void RewriteMacrosAction::ExecuteAction() {
   CompilerInstance &CI = getCompilerInstance();
   llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index dfea0c9..a9c1076 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -154,6 +154,7 @@ namespace {
     VarDecl *GlobalVarDecl;
 
     bool DisableReplaceStmt;
+    bool RewriteBlocksOnly;
 
     static const int OBJC_ABI_VERSION =7 ;
   public:
@@ -168,7 +169,8 @@ namespace {
     void HandleDeclInMainFile(Decl *D);
     RewriteObjC(std::string inFile, llvm::raw_ostream *OS,
                 Diagnostic &D, const LangOptions &LOpts,
-                bool silenceMacroWarn);
+                bool silenceMacroWarn,
+                bool rewriteBlocksOnly = false);
 
     ~RewriteObjC() {}
 
@@ -485,9 +487,10 @@ static bool IsHeaderFile(const std::string &Filename) {
 
 RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
                          Diagnostic &D, const LangOptions &LOpts,
-                         bool silenceMacroWarn)
+                         bool silenceMacroWarn, bool rewriteBlocksOnly)
       : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
-        SilenceRewriteMacroWarning(silenceMacroWarn) {
+        SilenceRewriteMacroWarning(silenceMacroWarn),
+        RewriteBlocksOnly(rewriteBlocksOnly) {
   IsHeader = IsHeaderFile(inFile);
   RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
                "rewriting sub-expression within a macro (may not be correct)");
@@ -504,6 +507,14 @@ ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile,
   return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
 }
 
+ASTConsumer *clang::CreateBlocksRewriter(const std::string& InFile,
+                                       llvm::raw_ostream* OS,
+                                       Diagnostic &Diags,
+                                       const LangOptions &LOpts,
+                                       bool SilenceRewriteMacroWarning) {
+  return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning, true);
+}
+
 void RewriteObjC::Initialize(ASTContext &context) {
   Context = &context;
   SM = &Context->getSourceManager();
@@ -545,76 +556,78 @@ void RewriteObjC::Initialize(ASTContext &context) {
 
   // declaring objc_selector outside the parameter list removes a silly
   // scope related warning...
-  if (IsHeader)
-    Preamble = "#pragma once\n";
-  Preamble += "struct objc_selector; struct objc_class; struct objc_super;\n";
-  Preamble += "struct __rw_objc_super { struct objc_object *object; ";
-  Preamble += "struct objc_object *superClass; ";
-  if (LangOpts.Microsoft) {
-    // Add a constructor for creating temporary objects.
-    Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
-                ": ";
-    Preamble += "object(o), superClass(s) {} ";
-  }
-  Preamble += "};\n";
-  Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
-  Preamble += "typedef struct objc_object Protocol;\n";
-  Preamble += "#define _REWRITER_typedef_Protocol\n";
-  Preamble += "#endif\n";
   if (LangOpts.Microsoft) {
     Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
     Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
   } else
-  Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
-  Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
-  Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret";
-  Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret";
-  Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
-  Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
-  Preamble += "(const char *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
-  Preamble += "(struct objc_class *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
-  Preamble += "(const char *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
-  Preamble += "(struct objc_class *, struct objc_object *);\n";
-  // @synchronized hooks.
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
-  Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
-  Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
-  Preamble += "struct __objcFastEnumerationState {\n\t";
-  Preamble += "unsigned long state;\n\t";
-  Preamble += "void **itemsPtr;\n\t";
-  Preamble += "unsigned long *mutationsPtr;\n\t";
-  Preamble += "unsigned long extra[5];\n};\n";
-  Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
-  Preamble += "#define __FASTENUMERATIONSTATE\n";
-  Preamble += "#endif\n";
-  Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
-  Preamble += "struct __NSConstantStringImpl {\n";
-  Preamble += "  int *isa;\n";
-  Preamble += "  int flags;\n";
-  Preamble += "  char *str;\n";
-  Preamble += "  long length;\n";
-  Preamble += "};\n";
-  Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
-  Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
-  Preamble += "#else\n";
-  Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
-  Preamble += "#endif\n";
-  Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
-  Preamble += "#endif\n";
+    Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+  if (!RewriteBlocksOnly) {
+    if (IsHeader)
+      Preamble = "#pragma once\n";
+    Preamble += "struct objc_selector; struct objc_class; struct objc_super;\n";
+    Preamble += "struct __rw_objc_super { struct objc_object *object; ";
+    Preamble += "struct objc_object *superClass; ";
+    if (LangOpts.Microsoft) {
+      // Add a constructor for creating temporary objects.
+      Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
+        ": ";
+      Preamble += "object(o), superClass(s) {} ";
+    }
+    Preamble += "};\n";
+    Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
+    Preamble += "typedef struct objc_object Protocol;\n";
+    Preamble += "#define _REWRITER_typedef_Protocol\n";
+    Preamble += "#endif\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
+    Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
+    Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret";
+    Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret";
+    Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
+    Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
+    Preamble += "(const char *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
+    Preamble += "(struct objc_class *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
+    Preamble += "(const char *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
+    Preamble += "(struct objc_class *, struct objc_object *);\n";
+    // @synchronized hooks.
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+    Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+    Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
+    Preamble += "struct __objcFastEnumerationState {\n\t";
+    Preamble += "unsigned long state;\n\t";
+    Preamble += "void **itemsPtr;\n\t";
+    Preamble += "unsigned long *mutationsPtr;\n\t";
+    Preamble += "unsigned long extra[5];\n};\n";
+    Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
+    Preamble += "#define __FASTENUMERATIONSTATE\n";
+    Preamble += "#endif\n";
+    Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
+    Preamble += "struct __NSConstantStringImpl {\n";
+    Preamble += "  int *isa;\n";
+    Preamble += "  int flags;\n";
+    Preamble += "  char *str;\n";
+    Preamble += "  long length;\n";
+    Preamble += "};\n";
+    Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
+    Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
+    Preamble += "#else\n";
+    Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
+    Preamble += "#endif\n";
+    Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
+    Preamble += "#endif\n";
+  }
   // Blocks preamble.
   Preamble += "#ifndef BLOCK_IMPL\n";
   Preamble += "#define BLOCK_IMPL\n";
@@ -650,9 +663,11 @@ void RewriteObjC::Initialize(ASTContext &context) {
     Preamble += "#define __block\n";
     Preamble += "#define __weak\n";
   }
-  // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
-  // as this avoids warning in any 64bit/32bit compilation model.
-  Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+  if (!RewriteBlocksOnly) {
+    // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
+    // as this avoids warning in any 64bit/32bit compilation model.
+    Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+  }
 }
 
 
@@ -674,23 +689,25 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
   if (Loc.isInvalid()) return;
 
   // Look for built-in declarations that we need to refer during the rewrite.
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
-    RewriteFunctionDecl(FD);
-  } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {
-    // declared in <Foundation/NSString.h>
-    if (FVD->getName() == "_NSConstantStringClassReference") {
-      ConstantStringClassReference = FVD;
-      return;
+  if (!RewriteBlocksOnly) {
+    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+      RewriteFunctionDecl(FD);
+    } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {
+      // declared in <Foundation/NSString.h>
+      if (FVD->getName() == "_NSConstantStringClassReference") {
+        ConstantStringClassReference = FVD;
+        return;
+      }
+    } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
+      RewriteInterfaceDecl(MD);
+    } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
+      RewriteCategoryDecl(CD);
+    } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+      RewriteProtocolDecl(PD);
+    } else if (ObjCForwardProtocolDecl *FP =
+               dyn_cast<ObjCForwardProtocolDecl>(D)){
+      RewriteForwardProtocolDecl(FP);
     }
-  } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
-    RewriteInterfaceDecl(MD);
-  } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
-    RewriteCategoryDecl(CD);
-  } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
-    RewriteProtocolDecl(PD);
-  } else if (ObjCForwardProtocolDecl *FP =
-             dyn_cast<ObjCForwardProtocolDecl>(D)){
-    RewriteForwardProtocolDecl(FP);
   } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
     // Recurse into linkage specifications
     for (DeclContext::decl_iterator DI = LSD->decls_begin(),
@@ -2099,6 +2116,8 @@ static void scanToNextArgument(const char *&argRef) {
 }
 
 bool RewriteObjC::needToScanForQualifiers(QualType T) {
+  if (RewriteBlocksOnly)
+    return false;
   if (T->isObjCQualifiedIdType())
     return true;
   if (const PointerType *PT = T->getAs<PointerType>()) {
@@ -2221,6 +2240,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
 }
 
 void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
+  if (RewriteBlocksOnly)
+    return;
   QualType QT = ND->getType();
   const Type* TypePtr = QT->getAs<Type>();
   if (!isa<TypeOfExprType>(TypePtr))
@@ -5656,29 +5677,31 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
     }
     return;
   }
-  if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
-    if (CompoundStmt *Body = MD->getCompoundBody()) {
-      CurMethodDef = MD;
-      CollectPropertySetters(Body);
-      CurrentBody = Body;
-      Body =
-       cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
-      MD->setBody(Body);
-      CurrentBody = 0;
-      if (PropParentMap) {
-        delete PropParentMap;
-        PropParentMap = 0;
+  if (!RewriteBlocksOnly) {
+    if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+      if (CompoundStmt *Body = MD->getCompoundBody()) {
+        CurMethodDef = MD;
+        CollectPropertySetters(Body);
+        CurrentBody = Body;
+        Body =
+         cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+        MD->setBody(Body);
+        CurrentBody = 0;
+        if (PropParentMap) {
+          delete PropParentMap;
+          PropParentMap = 0;
+        }
+        InsertBlockLiteralsWithinMethod(MD);
+        CurMethodDef = 0;
       }
-      InsertBlockLiteralsWithinMethod(MD);
-      CurMethodDef = 0;
     }
+    if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
+      ClassImplementation.push_back(CI);
+    else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
+      CategoryImplementation.push_back(CI);
+    else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
+      RewriteForwardClassDecl(CD);
   }
-  if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
-    ClassImplementation.push_back(CI);
-  else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
-    CategoryImplementation.push_back(CI);
-  else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
-    RewriteForwardClassDecl(CD);
   else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
     RewriteObjCQualifiedInterfaceTypes(VD);
     if (isTopLevelBlockPointerType(VD->getType()))
@@ -5735,17 +5758,21 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
   if (Diags.hasErrorOccurred())
     return;
 
-  RewriteInclude();
+  if (!RewriteBlocksOnly) {
+    RewriteInclude();
 
-  // Here's a great place to add any extra declarations that may be needed.
-  // Write out meta data for each @protocol(<expr>).
-  for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
-       E = ProtocolExprDecls.end(); I != E; ++I)
-    RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+    // Here's a great place to add any extra declarations that may be needed.
+    // Write out meta data for each @protocol(<expr>).
+    for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+         E = ProtocolExprDecls.end(); I != E; ++I)
+      RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+  }
 
   InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
-  if (ClassImplementation.size() || CategoryImplementation.size())
-    RewriteImplementations();
+  if (!RewriteBlocksOnly) {
+    if (ClassImplementation.size() || CategoryImplementation.size())
+      RewriteImplementations();
+  }
 
   // Get the buffer corresponding to MainFileID.  If we haven't changed it, then
   // we are done.
@@ -5757,13 +5784,15 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
     llvm::errs() << "No changes\n";
   }
 
-  if (ClassImplementation.size() || CategoryImplementation.size() ||
-      ProtocolExprDecls.size()) {
-    // Rewrite Objective-c meta data*
-    std::string ResultStr;
-    SynthesizeMetaDataIntoBuffer(ResultStr);
-    // Emit metadata.
-    *OutFile << ResultStr;
+  if (!RewriteBlocksOnly) {
+    if (ClassImplementation.size() || CategoryImplementation.size() ||
+        ProtocolExprDecls.size()) {
+      // Rewrite Objective-c meta data*
+      std::string ResultStr;
+      SynthesizeMetaDataIntoBuffer(ResultStr);
+      // Emit metadata.
+      *OutFile << ResultStr;
+    }
   }
   OutFile->flush();
 }
--
1.7.2.2.566.g36af9


commit 9663cf81240ff891ad292f576f789302f0582dd9
Author: Pierre Habouzit <[hidden email]>
Date:   Sat Oct 2 09:47:35 2010 +0200

    Introduce -rewrite-blocks
   
    Make it use a subset of the ObjC Rewriter.
   
    For now it basically does two things:
    - for one it tries to keep the language the code is written in, whether it
      is C, C++, ObjC or ObjC++, using RAII when the language is C++-based
    - it disables typeof and objc rewriting
   
    Signed-off-by: Pierre Habouzit <[hidden email]>

diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 512c2ca..7881972 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -351,6 +351,8 @@ def rewrite_test : Flag<"-rewrite-test">,
   HelpText<"Rewriter playground">;
 def rewrite_objc : Flag<"-rewrite-objc">,
   HelpText<"Rewrite ObjC into C (code rewriter example)">;
+def rewrite_blocks : Flag<"-rewrite-blocks">,
+  HelpText<"Rewrite C with blocks source to plain C99">;
 def rewrite_macros : Flag<"-rewrite-macros">,
   HelpText<"Expand macros without full preprocessing">;
 
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 4c16d08..2cbe940 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -46,6 +46,7 @@ namespace frontend {
     PrintPreamble,          ///< Print the "preamble" of the input file
     PrintPreprocessedInput, ///< -E mode.
     RewriteMacros,          ///< Expand macros but not #includes.
+    RewriteBlocks,          ///< C+Blocks -> C Rewriter
     RewriteObjC,            ///< ObjC->C Rewriter.
     RewriteTest,            ///< Rewriter playground
     RunAnalysis,            ///< Run one or more source code analyses.
diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/ASTConsumers.h
index 5fb107c..9ef7baa 100644
--- a/include/clang/Rewrite/ASTConsumers.h
+++ b/include/clang/Rewrite/ASTConsumers.h
@@ -34,6 +34,13 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile,
                                 const LangOptions &LOpts,
                                 bool SilenceRewriteMacroWarning);
 
+// Blocks rewriter: attempts to rewrite Blocks constructs into pure C code.
+ASTConsumer *CreateBlocksRewriter(const std::string &InFile,
+                                  llvm::raw_ostream *OS,
+                                  Diagnostic &Diags,
+                                  const LangOptions &LOpts,
+                                  bool SilenceRewriteMacroWarning);
+
 /// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
 /// HTML with syntax highlighting suitable for viewing in a web-browser.
 ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP,
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 2b5f88c..bd0c4f4 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -54,6 +54,12 @@ protected:
                                          llvm::StringRef InFile);
 };
 
+class RewriteBlocksAction : public ASTFrontendAction {
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile);
+};
+
 class RewriteMacrosAction : public PreprocessorFrontendAction {
 protected:
   void ExecuteAction();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d793fc0..1a64600 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -343,6 +343,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
   case frontend::PrintPreamble:          return "-print-preamble";
   case frontend::PrintPreprocessedInput: return "-E";
   case frontend::RewriteMacros:          return "-rewrite-macros";
+  case frontend::RewriteBlocks:          return "-rewrite-blocks";
   case frontend::RewriteObjC:            return "-rewrite-objc";
   case frontend::RewriteTest:            return "-rewrite-test";
   case frontend::RunAnalysis:            return "-analyze";
@@ -1035,6 +1036,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
       Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
     case OPT_rewrite_macros:
       Opts.ProgramAction = frontend::RewriteMacros; break;
+    case OPT_rewrite_blocks:
+      Opts.ProgramAction = frontend::RewriteBlocks; break;
     case OPT_rewrite_objc:
       Opts.ProgramAction = frontend::RewriteObjC; break;
     case OPT_rewrite_test:
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 63c6287..fe362d8 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -77,6 +77,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   case PrintPreamble:          return new PrintPreambleAction();
   case PrintPreprocessedInput: return new PrintPreprocessedAction();
   case RewriteMacros:          return new RewriteMacrosAction();
+  case RewriteBlocks:          return new RewriteBlocksAction();
   case RewriteObjC:            return new RewriteObjCAction();
   case RewriteTest:            return new RewriteTestAction();
   case RunAnalysis:            return new AnalysisAction();
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index 977e0cf..3f5cac7 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -98,6 +98,18 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
   return 0;
 }
 
+ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
+                                                    llvm::StringRef InFile) {
+  llvm::sys::Path Path(InFile);
+  llvm::Twine suffix("rw." + Path.getSuffix());
+
+  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, suffix.str()))
+    return CreateBlocksRewriter(InFile, OS,
+                                CI.getDiagnostics(), CI.getLangOpts(),
+                                CI.getDiagnosticOpts().NoRewriteMacros);
+  return 0;
+}
+
 void RewriteMacrosAction::ExecuteAction() {
   CompilerInstance &CI = getCompilerInstance();
   llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index dfea0c9..a9c1076 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -154,6 +154,7 @@ namespace {
     VarDecl *GlobalVarDecl;
 
     bool DisableReplaceStmt;
+    bool RewriteBlocksOnly;
 
     static const int OBJC_ABI_VERSION =7 ;
   public:
@@ -168,7 +169,8 @@ namespace {
     void HandleDeclInMainFile(Decl *D);
     RewriteObjC(std::string inFile, llvm::raw_ostream *OS,
                 Diagnostic &D, const LangOptions &LOpts,
-                bool silenceMacroWarn);
+                bool silenceMacroWarn,
+                bool rewriteBlocksOnly = false);
 
     ~RewriteObjC() {}
 
@@ -485,9 +487,10 @@ static bool IsHeaderFile(const std::string &Filename) {
 
 RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
                          Diagnostic &D, const LangOptions &LOpts,
-                         bool silenceMacroWarn)
+                         bool silenceMacroWarn, bool rewriteBlocksOnly)
       : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
-        SilenceRewriteMacroWarning(silenceMacroWarn) {
+        SilenceRewriteMacroWarning(silenceMacroWarn),
+        RewriteBlocksOnly(rewriteBlocksOnly) {
   IsHeader = IsHeaderFile(inFile);
   RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
                "rewriting sub-expression within a macro (may not be correct)");
@@ -504,6 +507,14 @@ ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile,
   return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
 }
 
+ASTConsumer *clang::CreateBlocksRewriter(const std::string& InFile,
+                                       llvm::raw_ostream* OS,
+                                       Diagnostic &Diags,
+                                       const LangOptions &LOpts,
+                                       bool SilenceRewriteMacroWarning) {
+  return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning, true);
+}
+
 void RewriteObjC::Initialize(ASTContext &context) {
   Context = &context;
   SM = &Context->getSourceManager();
@@ -545,6 +556,12 @@ void RewriteObjC::Initialize(ASTContext &context) {
 
   // declaring objc_selector outside the parameter list removes a silly
   // scope related warning...
+  if (LangOpts.Microsoft) {
+    Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
+    Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
+  } else
+    Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+  if (!RewriteBlocksOnly) {
   if (IsHeader)
     Preamble = "#pragma once\n";
   Preamble += "struct objc_selector; struct objc_class; struct objc_super;\n";
@@ -561,11 +578,6 @@ void RewriteObjC::Initialize(ASTContext &context) {
   Preamble += "typedef struct objc_object Protocol;\n";
   Preamble += "#define _REWRITER_typedef_Protocol\n";
   Preamble += "#endif\n";
-  if (LangOpts.Microsoft) {
-    Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
-    Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
-  } else
-  Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
   Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
   Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
   Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
@@ -615,6 +627,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
   Preamble += "#endif\n";
   Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
   Preamble += "#endif\n";
+  }
   // Blocks preamble.
   Preamble += "#ifndef BLOCK_IMPL\n";
   Preamble += "#define BLOCK_IMPL\n";
@@ -650,10 +663,12 @@ void RewriteObjC::Initialize(ASTContext &context) {
     Preamble += "#define __block\n";
     Preamble += "#define __weak\n";
   }
+  if (!RewriteBlocksOnly) {
   // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
   // as this avoids warning in any 64bit/32bit compilation model.
   Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
 }
+}
 
 
 //===----------------------------------------------------------------------===//
@@ -674,6 +689,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
   if (Loc.isInvalid()) return;
 
   // Look for built-in declarations that we need to refer during the rewrite.
+  if (!RewriteBlocksOnly) {
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     RewriteFunctionDecl(FD);
   } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {
@@ -691,6 +707,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
   } else if (ObjCForwardProtocolDecl *FP =
              dyn_cast<ObjCForwardProtocolDecl>(D)){
     RewriteForwardProtocolDecl(FP);
+    }
   } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
     // Recurse into linkage specifications
     for (DeclContext::decl_iterator DI = LSD->decls_begin(),
@@ -2099,6 +2116,8 @@ static void scanToNextArgument(const char *&argRef) {
 }
 
 bool RewriteObjC::needToScanForQualifiers(QualType T) {
+  if (RewriteBlocksOnly)
+    return false;
   if (T->isObjCQualifiedIdType())
     return true;
   if (const PointerType *PT = T->getAs<PointerType>()) {
@@ -2221,6 +2240,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
 }
 
 void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
+  if (RewriteBlocksOnly)
+    return;
   QualType QT = ND->getType();
   const Type* TypePtr = QT->getAs<Type>();
   if (!isa<TypeOfExprType>(TypePtr))
@@ -5656,6 +5677,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
     }
     return;
   }
+  if (!RewriteBlocksOnly) {
   if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
     if (CompoundStmt *Body = MD->getCompoundBody()) {
       CurMethodDef = MD;
@@ -5679,6 +5701,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
     CategoryImplementation.push_back(CI);
   else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
     RewriteForwardClassDecl(CD);
+  }
   else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
     RewriteObjCQualifiedInterfaceTypes(VD);
     if (isTopLevelBlockPointerType(VD->getType()))
@@ -5735,6 +5758,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
   if (Diags.hasErrorOccurred())
     return;
 
+  if (!RewriteBlocksOnly) {
   RewriteInclude();
 
   // Here's a great place to add any extra declarations that may be needed.
@@ -5742,10 +5766,13 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
   for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
        E = ProtocolExprDecls.end(); I != E; ++I)
     RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+  }
 
   InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
+  if (!RewriteBlocksOnly) {
   if (ClassImplementation.size() || CategoryImplementation.size())
     RewriteImplementations();
+  }
 
   // Get the buffer corresponding to MainFileID.  If we haven't changed it, then
   // we are done.
@@ -5757,6 +5784,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
     llvm::errs() << "No changes\n";
   }
 
+  if (!RewriteBlocksOnly) {
   if (ClassImplementation.size() || CategoryImplementation.size() ||
       ProtocolExprDecls.size()) {
     // Rewrite Objective-c meta data*
@@ -5765,5 +5793,6 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
     // Emit metadata.
     *OutFile << ResultStr;
   }
+  }
   OutFile->flush();
 }

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: -rewrite-objc and typeof (Was: -rewrite-objc, C and blocks)

jahanian
In reply to this post by Pierre Habouzit

On Oct 2, 2010, at 12:19 AM, Pierre Habouzit wrote:

On Fri, Oct 01, 2010 at 02:14:09PM -0700, jahanian wrote:

On Oct 1, 2010, at 1:42 PM, Pierre Habouzit wrote:


While I'm at it, the objc rewriter tries hard to rewrite typeof() for a
reason that eludes me.  Given that typeof() is often used inside macros,
and that rewriting inside macros may not work (that I can understand
;p), this is really painful.

We needed to support rewriting of __typeof because of our requirements.
There is a test case under Rewrite/rewrite-typeof.mm which specifically
tests this.

To be frank it still doesn't explain why you need it at all, but fine :)

This is one other reason to have a separate rewriter  without baggage
associated with our specific needs.

Well, I've made the work of taking the block rewriting code from
RewriteObjC.cpp, it's huge, and I'm uncomfortable duplicating that
amount of code.

So what is the best approach, is it writing a new RewriteBlocks class

You want a rewriter which rewrites a c program containing blocks into
a c program with all the block code synthesized into their underlying c
implementation.  This can be accomplished by declaring a new 
RewriteBlock class  derived from ASTConsumer. Pretty much follow how 
RewriteObjC object is constructed (and where) by setting
breakpoint in RewriteObjC::RewriteObjC and see how rewriter gets
called by setting breakpoint at clang::ParseAST. 
Then it is matter of lots of stripping off all the ObjC
rewriter stuff in code you bring from ObjC rewriter and
getting rid off all the c++-ness of block rewriting.
Rewriting of blocks is very substantive and what ObjC 
rewriter does involves code which interacts with NeXt''s 
block runtime. But you can rewrite a block which does
^{ printf("Hello");}();
pretty quickly.

- Fariborz

that RewriteObjC would inherit from (but it's a very huge work) or
simply make RewriteObjC have a "bool RewriteBlocksOnly" setting that is
selected whether it's called from -rewrite-objc or -rewrite-blocks on
the command line, and that would affect how code is generated ?

I'd rather go for the latter that is simpler, as mostly for now, it will
just disable the typeof rewriting, simplify the preamble (the objc stuff
isn't required), and keep my previous patch so that the generated code
still works when compiled with a c++ compiler.

Would that be acceptable ?
--
·O·  Pierre Habouzit
··O                                                [hidden email]
OOO                                                http://www.madism.org


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev