0

If I have a file clang.cpp containing:

#include <map>
void myfunc() {
    std::map<int, int> mymap;
    const int x = 20;
    myfoo[x] = 42;
}

and main.cpp containing:

void myfunc();
int main() { myfunc(); }

compiling clang++ -g clang.cpp -shared -fPIC -o libclang.so -stdlib=libstdc++ -std=c++11 and clang++ -g main.cpp -L -Wl.,-rpath=. -lclang -lstdc++ -o a.out -stdlib=libstc++ -std=c++11 will run fine.

However, if I add gcc.cpp containing:

#include <tuple>
template std::pair<int const, int>::pair(std::piecewise_construct_t, std::tuple<int const&>, std::tuple<>);

then also compile that to a shared library using g++ -g gcc.cp -shared -fPIC -o libgcc.so and change the linking command to clang++ -g main.cpp -L -Wl.,-rpath=. -lgcc -lclang -stdlib=libstdc++ -std=c++11 -o a.out, then running ./a.out will segment fault.

I don't know what to make of this, since clang and gcc are supposed to be ABI compatible when using the same c++ standard library. My versions are 3.6.2 for clang, 5.2.1 for gcc, as shipped with ubuntu.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
Darioush
  • 565
  • 3
  • 14
  • Since you're only declaring the specialization in one source file/translation unit this smells like an ODR violation. – Mark B Feb 23 '16 at 19:33
  • The template is instantiated in in both units: `myfoo[x] = 42` is where this get instantiated in the `clang.cpp` file. The way you get this in a realistic scenario is when `gcc.cpp` includes `unordered_map.h` and you have code similar to `clang.cpp` in that file. – Darioush Feb 23 '16 at 19:40
  • So you're saying that `main.cpp` also includes `gcc.cpp` to pick up the specialization? – Mark B Feb 23 '16 at 19:47
  • Sorry if I wasn't clear -- `libclang.so` and `libgcc.so` will contain the specialization. Also, the ODR doesn't apply to instantiated template (multiple definitions are allowed as long as they are token for token equivalent) – Darioush Feb 23 '16 at 20:01
  • 1
    You aren't allowed to do that. You can't just inject a specialization by linking against it. Every file in the final project must know that it's specialized at compile time or you violate the one definition rule (one specialized, one non-specialized). – Mark B Feb 23 '16 at 20:35
  • 1
    @MarkB It's not an explicit specialization; it's an explicit instantiation. Those are fine. – T.C. Feb 24 '16 at 09:07
  • GCC and Clang do pass `tuple`s differently. – T.C. Feb 24 '16 at 09:13
  • 1
    There is currently a large discussion on the ABI of passing empty types by value. It could be related. – Marc Glisse Feb 24 '16 at 09:20

1 Answers1

3

Given

int f(std::tuple<const int &> t){
  return std::get<0>(t);
}

Clang generates

f(std::tuple<int const&>):                    # @f(std::tuple<int const&>)
        movl    (%rdi), %eax
        retq

while GCC generates

f(std::tuple<int const&>):
        movq    (%rdi), %rax
        movl    (%rax), %eax
        ret

In other words, Clang is expecting the tuple itself to be passed by register, while GCC is expecting the address to be passed in register (and the tuple passed on the stack).

Mix and match and you get "fun" results.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Shorter example: `struct Tuple { int a; Tuple(Tuple&&); }; int f(Tuple t){ return t.a; }` – Marc Glisse Feb 24 '16 at 09:31
  • I am quite convinced that the bug is in clang (though the ABI could be clarified for C++11), it would be good if someone could report it there... – Marc Glisse Feb 24 '16 at 09:39
  • 1
    Discussion is going on here: http://sourcerytools.com/pipermail/cxx-abi-dev/2016-February/002884.html – Marc Glisse Feb 24 '16 at 21:40