<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - extern template classes, clang produces object code with 1 weak symbol, but ld gives undefined reference (ld accepts gcc object code)"
   href="https://bugs.llvm.org/show_bug.cgi?id=35239">35239</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>extern template classes, clang produces object code with 1 weak symbol, but ld gives undefined reference (ld accepts gcc object code)
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>5.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>jamespharvey20@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>With the commands and files below, the linker thinks there's an undefined
reference to "demo<int>::demo(int)", but it's in file2.o as a weak symbol.  g++
7.2.0 links an executable that runs fine.

My guess is when it's linking file1.o and sees the constructor as unlinked,
that it errors there without checking if it exists elsewhere.

clang properly handles extern template functions, but not extern template
classes.

Note clang gives the linker error both with "-std=c++11" and "-std=c++17".



$ clang++ -std=c++11 file1.cpp -c -o file1.o

$ clang++ -std=c++11 file2.cpp -c -o file2.o

$ clang++ -std=c++11 file1.o file2.o -o file
file1.o: In demoction `f()':
file1.cpp:(.text+0x1f): undefined reference to `demo<int>::demo(int)'
clang-5.0: error: linker command failed with exit code 1 (use -v to see
invocation)

$ clang++ -std=c++11 file2.o file1.o -o file -v
clang version 5.0.0 (tags/RELEASE_500/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-pc-linux-gnu/7.2.0
Found candidate GCC installation:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0
Found candidate GCC installation: /usr/lib64/gcc/x86_64-pc-linux-gnu/7.2.0
Selected GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0
Candidate multilib: .;@m64
Selected multilib: .;@m64
 "/usr/bin/ld" -pie --eh-frame-hdr -m elf_x86_64 -dynamic-linker
/lib64/ld-linux-x86-64.so.2 -o file
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/Scrt1.o
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/crti.o
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/crtbeginS.o
-L/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0
-L/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64
-L/usr/bin/../lib64 -L/lib/../lib64 -L/usr/lib/../lib64
-L/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/../../.. -L/usr/bin/../lib
-L/lib -L/usr/lib file2.o file1.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/crtendS.o
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/crtn.o
file1.o: In demoction `f()':
file1.cpp:(.text+0x1f): undefined reference to `demo<int>::demo(int)'
clang-5.0: error: linker command failed with exit code 1 (use -v to see
invocation)

$ nm --demangle file1.o
                 U __stack_chk_fail
0000000000000000 T f()
                 U demo<int>::demo(int)

$ nm --demangle file2.o
0000000000000050 T main
                 U __stack_chk_fail
                 U f()
0000000000000000 T g()
0000000000000000 W demo<int>::demo(int)

Compare to gcc's object code: (note gcc's compiler creates 2 weak symbols,
which doesn't seem right to me either, but it properly links, and what I think
is a local debugging symbol)

$ nm --demangle file2.o {on gcc's object file}
                 U _GLOBAL_OFFSET_TABLE_
000000000000003f T main
                 U __stack_chk_fail
                 U f()
0000000000000000 T g()
0000000000000000 W demo<int>::demo(int)
0000000000000000 W demo<int>::demo(int)
0000000000000000 n demo<int>::demo(int)



--- header.h ---
#pragma once

template<typename T>
class demo {
public:
   demo(T _) : value(_) {}
private:
   T value;
};

--- file1.cpp ---
#include "header.h"

extern template class demo<int>;

void f() {
   demo<int> i{42};
}

--- file2.cpp ---
#include "header.h"

void f();
void g() {
   demo<int> j{23};
}

int main() {
   f();
   g();
}</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>