Simple forward declaration compiles with g++ but not clang

86 views Asked by At

As for a minimally reproducible example, say I have the following class A defined in a header file a.h:

// file a.h
#include <cstdio>

class A {
private:
    int val;
public:
    A(int aVal) { val = aVal; }
    int getVal() { return val; }
};

And also I have a class Container defined via a container.h header and a container.cpp source

Header:

// file container.h
#include <cstdlib>
#include <new>

class A;

class Container {
private:
    unsigned int size = 0;
    A *data = nullptr;
public:
    Container();
    Container(int size);
    ~Container();

    A getElement(unsigned int pos); 

    template <typename... Args>
    void emplace(unsigned int pos, const Args & ...args);
};

template <typename... Args>
void Container::emplace(unsigned int pos, const Args & ...args)
{
    new(data + pos) A(args...);
}

Source:

// file container.cpp
#include "container.h"
#include "a.h"

Container::Container() {}

Container::Container(int size)
{
    data = static_cast<A*>(malloc(sizeof(A) * size));
}

Container::~Container()
{
    free(data);
    data = nullptr;
}

A Container::getElement(unsigned int pos)
{
    return data[pos];
}

For testing, I use the following main.cpp:

#include "a.h"
#include "container.h"


int main()
{
    A a(11);
    Container c(1);
    c.emplace(0, a);
    printf("%i\n", c.getElement(0).getVal()); // should print '11' to the console
    return 0;
}

When trying to compile and run the code, all works well with g++ (tested with versions 8 through 12). But clang throws the errors:

In file included from container.cpp:1:
./container.h:27:11: error: arithmetic on a pointer to an incomplete type 'A'
new(data + pos) A(args...);
            ~~~~ ^
./container.h:7:7: note: forward declaration of 'A'
class A;
      ^
./container.h:27:18: error: allocation of incomplete type 'A'
new(data + pos) A(args...);
                        ^
./container.h:7:7: note: forward declaration of 'A'
class A;
      ^
2 errors generated.

What could be going on? Is this a perhaps a clang bug? The code not only compiles, but works perfectly with g++ both in this minimal version I included here and in the much more complicated version from my real code. So it is not a mere "g++ is compiling broken stuff without warning".

Note that I did find a couple of previous questions that touch on analogous but different issues. For example, the question Nested classes with forward declaration cause an error in clang++, but pass without warning on g++ seems to also find problems with forward declaration with clang but the discussion there is specific about nested classes and namespaces. Another example is the question Confusion (or Clang bug?) about incomplete types in std::vector, also with clang giving weird behavior in the presence of forward declaration. But there the issue was related to subtle differences in specifying/not-specifying default constructors. A third example is the question Code compiles with g++ but not clang++ if incomplete type is used in templated function, but that relates to a ill-formed template, i.e. the problem of "a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter".

Hence, the problem I bring here may be related to those, but it is more generic and stripped down to the basics - illustrating a more pervasive problem with forward declaration that shows up only with clang.

Therefore my question: is there a way to alter my code above (of course, still using forward declaration of class A in container.h instead of including a.h within container.h) that will satisfy clang and g++ alike?

0

There are 0 answers