This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/58022] New: Compiler rejects abstract class in template class with friend operator<<


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58022

            Bug ID: 58022
           Summary: Compiler rejects abstract class in template class with
                    friend operator<<
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: scovich at gmail dot com

First, apologies for the vague subject line, I really don't know what to call
this bug...

Consider the following test case:

// <<<--- begin bug.cpp --->>>
#include <iostream>
using namespace std;
template <class T> class foo;
template <class T> ostream & operator<<(ostream& o, const foo<T>& l);
template <class T> class foo  {
    friend ostream& operator<< <T> (ostream& o, const foo<T>& l);
};
class bar;
foo<bar> fb;
class bar { virtual void baz()=0; };
// <<<--- end bug.cpp --->>>

The test case was isolated using multidelta on a large code base that compiles
cleanly with gcc-4.7 and earlier.

Compiling it with gcc-4.8.1 gives the error: "cannot allocate an object of
abstract type âbarâ", and identifying this function in <ostream>:

  template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
    { return __ostream_insert(__out, &__c, 1); }

Replacing "using namespace std" with "std::ostream" everywhere allows it to
compile, as does moving the definition of bar above the friend declaration.

I'm not 100% certain the code is valid C++, seeing as how it instantiates a
template using an incomplete type, but there are still several issues:

1. The compiler gives no hint whatsoever where the real problem is, leaving the
user to infer the context in some other way; it took 2h with multidelta to
isolate the above test case and finally "see" what had happened.

2. The declaration of operator<< (which accepts a const ref) should not
interfere with the one in <ostream> (which accepts a value); without the const
ref declaration the compiler (rightfully!) complains that "template-id
âoperator<< <bar>â for âstd::ostream& operator<<(std::ostream&, const
foo<bar>&)â does not match any template declaration"

3. At no point is bar actually instantiated, passed by value, or its members
accessed; even if operator<< did do one of those things, operator<< is never
actually called with foo<bar> as an argument, so the template shouldn't be
instantiated.

For now, the workaround seems to be ensuring that bar is fully defined before
any template class mentions it, but that's not going to be easy given how hard
it is to find the problem (and the fact that the foo template is in a utility
library and really should be included first under normal circumstances).

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]