Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

clang c++ virtual methods for templated class not instantiated with instantiation of constructor #6043

Closed Quuxplusone closed 14 years ago

Quuxplusone commented 14 years ago
Bugzilla Link PR5557
Status RESOLVED FIXED
Importance P normal
Reported by Eli Friedman (efriedma@quicinc.com)
Reported on 2009-11-18 22:10:57 -0800
Last modified on 2010-02-22 12:53:18 -0800
Version unspecified
Hardware PC Linux
CC andersca@icloud.com, cdavis5x@gmail.com, dgregor@apple.com, llvm-bugs@lists.llvm.org, sebastian.redl@getdesigned.at
Fixed by commit(s)
Attachments virtual-function-instantiation-fail.patch (3035 bytes, text/plain)
instantiate-virtual.cpp (369 bytes, text/plain)
Blocks PR5511
Blocked by
See also
Testcase:
template <class T> struct A {
  A();
  virtual int a(T x);
};
template<class T> A<T>::A() {}
template<class T> int A<T>::a(T x) { return *x; }
A<int> x;
int main() { return 0; }

Output (clang x.cpp -fno-rtti):
/tmp/cc-nJeNb1.o:(.gnu.linkonce.r._ZTV1AIiE+0x8): undefined reference to
`A<int>::a()'
collect2: ld returned 1 exit status
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Compare to output from g++:
/tmp/x.cpp: In member function ‘int A<T>::a(T) [with T = int]’:
/tmp/x.cpp:10:   instantiated from here
/tmp/x.cpp:8: error: invalid type argument of ‘unary *’
Quuxplusone commented 14 years ago

We need to instantiate the virtual functions of an implicitly-instantiated class template specialization (or member class thereof) when we're going to emit a vtable. Right now, that decision is made by CodeGen, but we'll need to boost it up into Sema so that we can make sure that all of the virtual functions will get instantiated when CodeGen is going to need them.

Quuxplusone commented 14 years ago

The standard gives us a lot of leeway there. If we want, we can instantiate virtual members the moment the containing class is instantiated.

Quuxplusone commented 14 years ago

Attached instantiate-virtual.cpp (369 bytes, text/plain): Test case that illustrates the specialization-after-instantiation problem

Quuxplusone commented 14 years ago

I tried implementing that approach, where we instantiate virtual member functions along with the class itself, but I was running into specialization-after-instantiation errors in libstdc++. See the attached patch and test case.

I think we'll need to figure out what GCC does and mimic that.

Quuxplusone commented 14 years ago

Attached virtual-function-instantiation-fail.patch (3035 bytes, text/plain): Failed attempt at instantiating virtual member functions with the class

Quuxplusone commented 14 years ago
(In reply to comment #5)
> I think we'll need to figure out what GCC does and mimic that.

I believe what gcc does is that at the end of file, for any templated class, it
checks whether the vtable is needed; if it is, it defines the vtable and
instantiates the functions referred to by the vtable.  As proof, note that for
the following testcase, the instantiation error comes *after* the error about
b(), even though there isn't anything interesting in the file after it:
template <class T> struct A {
  virtual int a(T x);
};
template<class T> int A<T>::a(T x) { return *x; }
A<int>* a() { return new A<int>; }
void b() { return 1; }
//template<> int A<int>::a(int x) { return 2; }

It's extremely nasty, but if libstdc++ depends on it, I don't really see an
alternative.
Quuxplusone commented 14 years ago
(In reply to comment #6)
> (In reply to comment #5)
> > I think we'll need to figure out what GCC does and mimic that.
>
> I believe what gcc does is that at the end of file, for any templated class,
it
> checks whether the vtable is needed; if it is, it defines the vtable and
> instantiates the functions referred to by the vtable.  As proof, note that for
> the following testcase, the instantiation error comes *after* the error about
> b(), even though there isn't anything interesting in the file after it:
> template <class T> struct A {
>   virtual int a(T x);
> };
> template<class T> int A<T>::a(T x) { return *x; }
> A<int>* a() { return new A<int>; }
> void b() { return 1; }
> //template<> int A<int>::a(int x) { return 2; }
>
> It's extremely nasty, but if libstdc++ depends on it, I don't really see an
> alternative.

FWIW, GCC (and Clang, and EDG) instantiate functions at the end of the
translation unit regardless of where the actual point of instantiation was.
It's possible that the synthesis of the definition of the default constructor
is also being delayed until the end of the file and that, in turn, forces the
instantiation of the non-pure virtuals in the class (because a vtable is
needed).
Quuxplusone commented 14 years ago

Committed revision 90753.

Quuxplusone commented 14 years ago

I don't know... I still get link errors related to the std::basic_istream class. I don't know if this is a separate issue or what, but std::basic_istream still isn't getting instantiated properly.

Quuxplusone commented 14 years ago

Never mind, it's fixed in SVN. Thanks, Anders!