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: "Martin v. Loewis" <martin at mira dot isdn dot cs dot tu-berlin dot de>
- Subject: Re: gcc 2.95.1 can't compile correnct code (SUN's CC can)
- From: Rainer Dorsch <rainer at rainer dot informatik dot uni-stuttgart dot de>
- Date: Sat, 30 Oct 1999 15:55:01 +0300
- Cc: kellermo at ramona dot informatik dot uni-stuttgart dot de, gcc at gcc dot gnu dot org
- Reply-To: rainer dot dorsch at informatik dot uni-stuttgart dot de
Martin,
thanks for the detailed explanation. Especially the reference to the standard
is very valuable, if the goal is portable code.
Thanks.
--Rainer.
> > 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
--
Rainer Dorsch
Abt. Rechnerarchitektur e-mail:rainer.dorsch@informatik.uni-stuttgart.de
Uni Stuttgart Tel.: 0711-7816-215