nasa / trick

Trick Simulation Environment. Trick provides a common set of simulation capabilities and utilities to build simulations automatically.
Other
44 stars 22 forks source link

Uncompilable io_src code for templates that instantiate templates #1169

Open dbankieris opened 3 years ago

dbankieris commented 3 years ago

ICG produces iosrc code for a particular instantiation of a template in the `io*.cppof the containing class via [FieldVisitor::ProcessTemplate`](https://github.com/nasa/trick/blob/0825b321183f71c1c54ebf4c6310660a4c1dbb1f/trick_source/codegen/Interface_Code_Gen/FieldVisitor.cpp#L291).

// Foo.hh
template <class T> class Foo {};
// Bar.hh
#include "Foo.hh"
class Bar {
    Foo<int> fint;
    Foo<double> fouble;
};

I/O code for Foo<int> and Foo<double> is produced in io_Bar.cpp.

// io_Bar.cpp
ATTRIBUTES attrBar_fint_Foo_int_[] = {
// more Foo<int> stuff

ATTRIBUTES attrBar_fouble_Foo_double_[] = {
// more Foo<double> stuff

If a template instantiates another template as a member variable, an io_*.cpp is created for the containing template.

// Baz.hh
#include "Foo.hh"
template <class T>
class Baz {
    Foo<T> foot;
};
// Potato.hh
#include "Baz.hh"

class Onion {};

class Potato {
    Baz<int> bint;
    Baz<double> bouble;
    Baz<Onion> bonion;
};

I/O code for Baz<int>, Baz<double>, and Baz<Onion> is created in io_Potato.cpp as usual.

// io_Potato.cpp
ATTRIBUTES attrPotato_bint_Baz_int_[] = {
ATTRIBUTES attrPotato_bouble_Baz_double_[] = {
ATTRIBUTES attrPotato_bonion_Baz_Onion_[] = {

I/O code for Foo<int>, Foo<double>, and Foo<Onion> is produced in io_Baz.cpp (which would normally not be created at all) because that's where the instantiations of Foo occur.

// io_Baz.cpp
ATTRIBUTES attrBaz_foot_Foo_int_[] = {
ATTRIBUTES attrBaz_foot_Foo_double_[] = {
ATTRIBUTES attrBaz_foot_Foo_Onion_[] = {

The problem here is that Onion is defined in Potato.hh, which is not known to Baz.hh, which is the only header that io_Baz.cpp includes. The result is uncompilable I/O code.

io_Baz.cpp: In function ‘size_t io_src_sizeof_Baz_foot_Foo_Onion_()’:
io_Baz.cpp:144:23: error: ‘Onion’ was not declared in this scope
     return sizeof(Foo<Onion>) ;

Including Potato.hh in io_Baz.cpp fixes it, but I'm not sure if that's a general solution or how to even figure out that's necessary from within ICG. The header defining a particular type could be an arbitrary number of levels up the include chain. Perhaps the I/O code for Foo<int>, Foo<double>, and Foo<Onion> should go in io_Potato.cpp instead?

Possibly related to #540 and #1001

@alexlin0 Thoughts?

alexlin0 commented 3 years ago

I remember this. This has been a limitation from the beginning. I don't remember the details, but I do remember running into this exact scenario. I've been away from the code too long to give any suggestions off the top of my head on how we can fix this.