doctaweeks / include-what-you-use

Automatically exported from code.google.com/p/include-what-you-use
Other
0 stars 0 forks source link

forward declaring classes used in template functions that do not allow incomplete types #175

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
clang/llvm/iwyu trunk (3.7)

iwyu forward declares classes used in template functions that do not allow 
incomplete types (e.g., std::pair<_T1,_T2>).  This is similar to the problem of 
forward declaring classes used in catch().

If I have a class defined in a namespace in 

Example below of a header file:
#include <string>
#include "variant.hpp" //declares ESM::Variant
namespace ESM
{
    class ESMReader;
    class ESMWriter;
    struct Locals
    {
        std::vector<std::pair<std::string, Variant> > mVariables;
        void load (ESMReader &esm);
        void save (ESMWriter &esm) const;
    };
}

iwyu says:
components/esm/locals.hpp should add these lines:
#include <utility>                      // for pair
namespace ESM { class Variant; }
//end of file

components/esm/locals.hpp should remove these lines:
- #include "variant.hpp"  // lines 7-7

The full include-list for components/esm/locals.hpp:
#include <string>                       // for string
#include <utility>                      // for pair
#include <vector>                       // for vector
namespace ESM { class ESMReader; }  // lines 11-11
namespace ESM { class ESMWriter; }  // lines 12-12
namespace ESM { class Variant; }
end file

However, replacing #include "variant.hpp" with namespace ESM { class Variant; } 
causes the error:
bits/stl_pair.h:102:11: error: field has incomplete type 'ESM::Variant'

since std::pair can't take incomplete types.

thank you! (btw, I'm not a c++ guy, CS, or would even call myself a programmer, 
so please excuse any mistakes in my reports)

Original issue reported on code.google.com by showard...@gmail.com on 7 Feb 2015 at 5:41

GoogleCodeExporter commented 9 years ago
Don't know whether this is related, but might also happen with member functions 
of template classes:
error: member access into incomplete type

Example, a member function is defined in a header file:

//headerfile
namespace somenamespace
{
  template <class T> //don't know if this only happens for template classes
  class Store : public StoreBase
  {
    public:
      void write (ESM::ESMWriter& writer) const
      {
        writer.startRecord (T::sRecordId);
      }
   }
}

iwyu says i should add
namespace ESM { class ESMWriter; }

and should remove:
#include <components/esm/esmwriter.hpp>  // lines 10-10

which then would cause
error: member access into incomplete type

(full example file here: 
https://github.com/OpenMW/openmw/blob/master/apps/openmw/mwworld/store.hpp)

Original comment by showard...@gmail.com on 7 Feb 2015 at 5:58

GoogleCodeExporter commented 9 years ago
Thanks for the bug report, showard314. I was able to reproduce it with 
`std::vector<std::pair<int, IndirectClass> >`. By the way, just `std::pair<int, 
IndirectClass>` requires full use of IndirectClass. My current guess is that we 
correctly detect we need full use of std::pair, but we don't check full use, 
forward-declare use for std::pair template arguments.

Original comment by vsap...@gmail.com on 10 Feb 2015 at 3:21

GoogleCodeExporter commented 9 years ago
I just came across this same bug*, but I'd just like to note that when the 
class has both vector<pair<string,string>> and plain string member variables, 
it still recommends to use iosfwd instead of string. Is there any known 
workaround for this?

Original comment by douwegel...@gmail.com on 27 Mar 2015 at 1:25

GoogleCodeExporter commented 9 years ago
It's not helpful, but I think the problem with iosfwd is issue #80, especially 
if you are using libc++, not libstdc++.  And unfortunately I don't know any 
workarounds for it.

Original comment by vsap...@gmail.com on 31 Mar 2015 at 6:10

GoogleCodeExporter commented 9 years ago
Hi,
same problem happens in case of using std::make_shared<>.  In example code, for 
given function *declaration*:

void f(std::shared_ptr<X> x, std::shared_ptr<Y> y = std::make_shared<YImpl>);

IWYU correctly use forward declaration for X type. However it also consider Y 
and YImpl as candidates for forward-declare, which is obviously wrong.

BTW: would be possible to provide some kind of forward-declare blacklisting 
mechanism for given language constructs (and possibly types)? It would solve 
98% of my issue with IWYU if I could somehow tell IWYU to never use 
forward-declare when type appears in context of make_shared and catch().

Original comment by marianbe...@gmail.com on 3 May 2015 at 9:36

GoogleCodeExporter commented 9 years ago
See if you can use the ``no_forward_declare`` pragma:
https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas#IWYU_pragma:_no_
forward_declare

It might provide the crutch you need.

Original comment by kim.gras...@gmail.com on 3 May 2015 at 10:02

GoogleCodeExporter commented 9 years ago
If I understand "no_forward_declare" correctly, this would have to be done in 
each and every file that use either make_shared or catch for each type that 
appear there. My project has more than 5000 quite often changing files and we 
use dependency injection all over the place, in many cases using shared_ptrs, 
so unfortunately it wouldn't be practical to do this manually. If it would be 
only couple of places I guess I could also use pragma 'keep' to avoid this 
issue, but sadly I can't.
Maybe it would be a little easier if I could use 'no_forward_declare' right 
next to class definition (i.e. in same file), but probably still quite hard.

Original comment by marianbe...@gmail.com on 3 May 2015 at 12:30