-rewrite-objc, C and blocks

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 ?

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

0001-Try-to-make-rewrite-objc-result-buildable-by-a-C-com.patch (7.54 KB)

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

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 :slight_smile:

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

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.

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 :slight_smile:

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

- Fariborz

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.

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

>
> 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 :slight_smile:

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.

0001-Try-to-make-rewrite-objc-result-buildable-by-a-C-com.patch (7.51 KB)

0002-Introduce-rewrite-blocks.patch (23.8 KB)

0002-Introduce-rewrite-blocks.IGNORE_BLANKS.patch (13.6 KB)

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 :slight_smile:

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