godard@CURLY.SAMSUNG.COM (Ivan Godard) (08/25/89)
We use the block expression language extension "( {...} )" of your compilers to cope with the compiler's problems with function types. We use function data extensively, as variables, as record components, and as parameters and results of other functions. Because of abstraction, we often have to cast from one function type to another, which causes the compilers trouble as you know. Our solution was to write a macro: #define AsFunc(rt, p, v) \ ({\ typedef rt (*F)p;\ (F)v;\ }) which gets called with something like: AsFunc(void, (char*, int), Foo) to give Foo the type "void(*)(char*, int)", which the compiler can't handle in expression context like this. We have found that using these casts in the parameter lists to function calls gives incorrect code. I have cut down an example to tractable size. Example follows (the call which gives problems is marked):: ----------------------------------------------------------------------------- typedef char headerClass; typedef union { headerClass headerClass; /* format */ struct { headerClass headerClass; /* commitHeader */ long who; long where; } commit; struct { headerClass headerClass; /* format */ char isBasket:1; /* basket flag */ char isThunk:1; /* virtual object flag */ long oid; /* the object's own id, for recovery */ long basket; /* and the basket it was written under */ int dataLength; int relocLength; int handleLength; } data; } objectHeader; void WriteData( objectHeader* loc, void (*Data)(long, char*), int size, char* state) { ; }; extern long MarkAccum(int); long WriteObject( long id, long trans, long occupied, long oids, long relocs) { long acc; objectHeader* loc; objectHeader header; acc = MarkAccum(sizeof(objectHeader)); loc->data.isBasket = header.data.isBasket; WriteData(loc, /* <===================== this call */ ({typedef void(*F)(long, char*); (F)WriteObject; }), sizeof(objectHeader), 0); return id; }; --------------------------------------------------------------------------- end of example. The result of compilation is: emitted code follows (bad instruction marked): --------------------------------------------------------------------------- #NO_APP gcc_compiled.: .text .even .globl _WriteData _WriteData: link a6,#0 unlk a6 rts .even .globl _WriteObject _WriteObject: link a6,#-24 movel a2,sp@- pea 22:w jbsr _MarkAccum bfexts a6@(-21){#0:#1},d0 bfins d0,a2@(1){#0:#1} clrl sp@- pea 22:w addqw #4,sp <============== bad instruction pea _WriteObject movel a2,sp@- jbsr _WriteData movel a6@(8),d0 movel a6@(-28),a2 unlk a6 rts --------------------------------------------------------------------------- end of emitted code While this example is certainly not minimal, at least some of the monkey puzzle before the call sems to be necessary for the error. When there is more puzzle there, the amount that the stack gets cut back by the erroneous instruction increases. We have examples of similar stack cuts when the blocks are used in other context than a call. It is not clear whether the offence has to do with the block expression or the functional type; perhaps both. It appears in both optimized and non optimized code. Given the same input, g++ does not cause the error. Happy debugging! Ivan