This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: gcc 2.95.1 can't compile correnct code (SUN's CC can)
- To: rainer dot dorsch at informatik dot uni-stuttgart dot de
- Subject: Re: gcc 2.95.1 can't compile correnct code (SUN's CC can)
- From: "Martin v. Loewis" <martin at mira dot isdn dot cs dot tu-berlin dot de>
- Date: Sat, 30 Oct 1999 15:41:12 +0200
- CC: gcc at gcc dot gnu dot org, kellermo at cs dot tu-berlin dot de
- References: <m11hYGV-000HVzC@rainer.informatik.uni-stuttgart.de>
> Thanks for the clarification. Is this a limitation of C++ template concept:
It's not a limitation of the C++ templates, but rather a side effect
of the list template.
> If I would implement the list myself (non-templete, something like
> list_b), I wouldn't need a complete type of b, because my list
> implementation would contain only pointers to b, because it has no
> instance of b when the constructor is called.
g++ is quite specific about the actual cause. You write
a(){}
This is the default constructor; it invokes the default constructors
for all members, in particular:
explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}
When this template is instantiated and invoked, it in turn
instantiates the base class (of std::list, which is internal):
_List_base(const allocator_type& __a) : _Base(__a) {
_M_node = _M_get_node();
_M_node->_M_next = _M_node;
_M_node->_M_prev = _M_node;
}
This, in turn, invokes _M_get_node:
_List_node<_Tp>* _M_get_node() { return _Alloc_type::allocate(1); }
This allocates one element:
static _Tp* allocate(size_t __n)
{ return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); }
which in turns needs to find out the size of a list node, which is
template <class _Tp>
struct _List_node {
typedef void* _Void_pointer;
_Void_pointer _M_next;
_Void_pointer _M_prev;
_Tp _M_data;
};
which contains a member of type b (_M_data). Hence the error that you
are using an incomplete type.
Now, I agree there are alternatives which would avoid this
problem. Also, I withdraw my earlier claim that Sun CC should have
detected that error. The effect of your code is explained in 17.4.3.6,
[lib.res.on.functions]:
# 1 In certain cases (replacement functions, handler functions,
# operations on types used to instantiate standard library template
# components), the C++ Standard Library depends on components supplied
# by a C++ program. If these components do not meet their
# requirements, the Standard places no requirements on the
# implementation.
#
# 2 In particular, the effects are undefined in the following cases:
[...]
# - if an incomplete type (3.9) is used as a template argument when
# instantiating a template component.
So the effect of your program is undefined. It may compile on one
compiler, and fail to compile on another. If it compiles, it may have
the effect you want, or it may cause a power-outage in your city.
If you want to compile your program with g++, moving the constructor
out-of-line will work around the problem:
#include<list>
using namespace std;
class b;
class a{
public:
a();
list<b> c;
};
class b{
public:
b(){}
list<a> d;
};
a::a(){}
int main(){
a x;
b y;
exit(0);
}
Please note that this is code has still undefined behaviour; it just
happens (by coincidence) that gcc 2.95 accepts it.
Hope this helps,
Martin