From: William S F. <ws...@fu...> - 2013-11-27 23:02:54
|
On 26/11/13 13:59, Vladimir Kalinin wrote: >>> This is a reduced example of a valid C, but invalid C++: >>> struct Outer { >>> int foo; >>> struct Nested { >>> int bar; >>> }; >>> }; >>> void f(struct Nested* s){} >>> >>> >> I was wondering if for Octave we could always infer -c++. However, I >> don't think this is a good idea as the parser works differently parsing >> C code, and so it could break parsing perfectly valid C code. >> >> I was trying to think of some work around by generating code within a >> #if __cplusplus block, but I havn't managed to come up with anything >> reasonable. I think we will have to generate C++ accessors, that is: >> 'Outer::Nested*' instead of 'struct Nested*' when accessing this inner >> struct for languages that compile the wrappers as C++. >> >> What we need is a new mode, say CPlusPlusOut, that knows to read C as >> input and generate valid C++ as output. This mode should be set by >> Octave in the absence of -c++ and then where necessary, valid C++ can be >> generated for the nested structs. Vladimir, can you look at implementing >> this? >> >> This definitely needs addressing as normally in the default case, SWIG >> tries very hard to generate code which will compile and clearly fails >> completely in this case. >> > > > The problem is, that, if the code I quoted will be included verbatim in the > generated c++ wrappers, the wrappers won't compile, whatever we generate. > (That applies mostly to GCC/llvm, Microsoft compiler is more relaxed in > that case. (Can't say anything about ancient compilers like SunPro, > etc.)) > > Interestingly, I found your code above will compile as C++ using a variety of compilers - g++/clang++/vc++. I'm not sure of the relevant part in the standard (possibly 9.9 in C++98), but it looks like the declaration of Nested introduces a forward class declaration in the global namespace when compiled as C++. This is clear from compiler messages when attempting to use it, for example, using: void ff(struct Nested* s) { s->bar = 0; } results in: runme.cxx: In function ‘void ff(Nested*)’: runme.cxx:27:6: error: invalid use of incomplete type ‘struct Nested’ s->bar = 0; ^ runme.cxx:26:16: error: forward declaration of ‘struct Nested’ void ff(struct Nested* s) { ^ I'm sure we can generate appropriate code to deal with this case thhrough judicious choice of casts to either Outer::Nested* or Nested*. On the other hand, wrapping pass by value does not compile as the nested class is incomplete, for example adding this: void fff(struct Nested s); I don't see any way to generate code to handle this case using careful casting. However, there seems to be a trick we could employ to make this work by copying the nested struct into the global C++ namespace. For example wrapping: %inline %{ struct Outer { int foo; struct Nested { int bar; } nested; }; void f(struct Nested* s); void fff(struct Nested s); %} will work in Octave using your new nested patch merely by adding this to the generated code: struct Nested { int bar; }; before any usage of Nested in the wrappers. I think this trick is perfectly reasonably as it pretty much implements what is suggested in http://david.tribble.com/text/cdiffs.htm#C99-nested-struct. Vladimir, do you think you could make some modifications to try this out implementing it using the CPlusPlusOut option mentioned earlier? It probably involves reviving some of the old code you've removed that regenerated the C structs into the output wrappers, but this time you'd generate the above instead of: typedef struct { int bar; } Outer_nested; Interestingly, fff did not work in Octave using the old nested struct wrapping, but with this change it would :) William |