Missing definition of a template virtual function

Srivastava, Sunil via cfe-commits cfe-commits at lists.llvm.org
Fri May 27 13:03:38 PDT 2016


Hi,

I want to discuss the issue in PR27895,
       https://llvm.org/bugs/show_bug.cgi?id=27895

But I will give a slightly different example for this discussion.

The issue can be demonstrated by this standalone code. Should this example link
successfully?
----------------------------------------------
template < typename T, int N = 0 > class TmplWithArray {
public:
  virtual T& operator [] (int idx);
  T ar[N+1];
};
template <typename T, int N> T& TmplWithArray<T, N >::operator[](int idx) {
  return ar[idx];
}
class Wrapper {
  TmplWithArray<bool, 10> data;
  bool indexIt(int a);
};
bool Wrapper::indexIt(int a)
{
   return data[a];
}
int main(){}
----------------------------------------------

Starting from  r227073 it does not link (at any optimization level). The code
has a direct call to the operator[] function, but that function definition is
not generated.

Versions prior to r227073,
    -  at -O0 or -O1, generate the operator[] function and the direct call, and
    -  at -O2 do not generate the function, but inline it
Either way they link fine.

In this example the key-function for the generation of the vtable is the
operator[] function itself.

So the compiler can either generate both the vtable and the operator[]
function, or not generate either; they are both consistent states.

The call in data[a] is to a virtual function, and if the compiler left it as a
virtual call, it will link. There will be no ctor, no vtable, and no operator[]
function. Wrapper::indexIt will be dead code, but it will link.

But the compiler does devirtualization of the call and generates a direct call,
yet, beginning with r227073, it does not generate the operator[] function.
Hence the link failure.

Another interesting tidbit is that if the operator[] is replaced by a plain
function doing the same thing, along with the corresponding change in the
usage, something like:
    virtual T& getElt(int idx);
then the behavior is the same as pre r227073. Either getElt is defined or it
gets inlined.

BTW, this is not just an idle curiosity. This example was trimmed down from
a user bug report having a link failure.

Sunil Srivastava
Sony Interactive Entertainment
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160527/44e165b1/attachment-0001.html>


More information about the cfe-commits mailing list