llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.15k stars 12.02k forks source link

link success with static template member depends on optimisation level #20967

Closed llvmbot closed 10 years ago

llvmbot commented 10 years ago
Bugzilla Link 20593
Resolution INVALID
Resolved on Aug 14, 2014 02:39
Version 3.4
OS FreeBSD
Reporter LLVM Bugzilla Contributor
CC @majnemer,@DougGregor

Extended Description

First of all I do not know whether static template members are permitted. I figure there are some initialisation issues for the linker to sort out if a template is used in multiple object files.

In any way I think the behaviour should be the same for all optimisation levels.

EXAMPLE CODE

--- foo.hpp ---

ifndef _FOOHPP

define _FOOHPP

template class foo { private: static T static_member;

    public:
    foo() {
    }

    static T const & static_method() {
            return foo<T>::static_member;
    }

    T const & dynamic_method() const {
            return this->static_member;
    }

};

endif / _FOOHPP /

--- main.cpp ---

include "foo.hpp"

int main() { foo bar; bar.dynamic_method(); foo::static_method(); return 0; }

CLANG VERSION

c++ -v FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512 Target: x86_64-unknown-freebsd10.0 Thread model: posix Selected GCC installation:

OS

uname -a FreeBSD AprilRyan.norad 10.0-STABLE FreeBSD 10.0-STABLE #​0 r268659: Tue Jul 15 11:25:22 CEST 2014 root@AprilRyan.norad:/usr/obj/S403/amd64/usr/src/sys/S403 amd64

DIRECT COMPILE

c++ -O0 main.cpp /tmp/main-b8dc96.o: In function foo<int>::dynamic_method() const': main.cpp:(.text._ZNK3fooIiE14dynamic_methodEv[_ZNK3fooIiE14dynamic_methodEv]+0x8): undefined reference tofoo::static_member' /tmp/main-b8dc96.o: In function foo<int>::static_method()': main.cpp:(.text._ZN3fooIiE13static_methodEv[_ZN3fooIiE13static_methodEv]+0x8): undefined reference tofoo::static_member' c++: error: linker command failed with exit code 1 (use -v to see invocation)

c++ -O1 main.cpp /tmp/main-17cbe6.o: In function foo<int>::dynamic_method() const': main.cpp:(.text._ZNK3fooIiE14dynamic_methodEv[_ZNK3fooIiE14dynamic_methodEv]+0x5): undefined reference tofoo::static_member' /tmp/main-17cbe6.o: In function foo<int>::static_method()': main.cpp:(.text._ZN3fooIiE13static_methodEv[_ZN3fooIiE13static_methodEv]+0x5): undefined reference tofoo::static_member' c++: error: linker command failed with exit code 1 (use -v to see invocation)

c++ -O2 main.cpp ll total 16 -rwxr-xr-x 1 kamikaze kamikaze 7371 8 Aug 15:30 a.out* -rw-r--r-- 1 kamikaze kamikaze 295 8 Aug 15:04 foo.hpp -rw-r--r-- 1 kamikaze kamikaze 113 8 Aug 15:08 main.cpp

COMPILE FIRST LINK LATER

c++ -c -O0 main.cpp c++ -O0 main.o main.o: In function foo<int>::dynamic_method() const': main.cpp:(.text._ZNK3fooIiE14dynamic_methodEv[_ZNK3fooIiE14dynamic_methodEv]+0x8): undefined reference tofoo::static_member' main.o: In function foo<int>::static_method()': main.cpp:(.text._ZN3fooIiE13static_methodEv[_ZN3fooIiE13static_methodEv]+0x8): undefined reference tofoo::static_member' c++: error: linker command failed with exit code 1 (use -v to see invocation)

c++ -c -O1 main.cpp c++ -O1 main.o main.o: In function foo<int>::dynamic_method() const': main.cpp:(.text._ZNK3fooIiE14dynamic_methodEv[_ZNK3fooIiE14dynamic_methodEv]+0x5): undefined reference tofoo::static_member' main.o: In function foo<int>::static_method()': main.cpp:(.text._ZN3fooIiE13static_methodEv[_ZN3fooIiE13static_methodEv]+0x5): undefined reference tofoo::static_member' c++: error: linker command failed with exit code 1 (use -v to see invocation)

c++ -c -O2 main.cpp c++ -O2 main.o ll total 20 -rwxr-xr-x 1 kamikaze kamikaze 7371 8 Aug 15:35 a.out* -rw-r--r-- 1 kamikaze kamikaze 295 8 Aug 15:04 foo.hpp -rw-r--r-- 1 kamikaze kamikaze 113 8 Aug 15:08 main.cpp -rw-r--r-- 1 kamikaze kamikaze 1256 8 Aug 15:35 main.o

llvmbot commented 10 years ago

Optimizers are scary …

Sorry for the noise!

991901f3-cc14-4404-b340-165691b62a58 commented 10 years ago

The optimizer is still able to prove that it doesn't need to reference the actual static.

The following is an example that will have a linker error under all levels of optimizations: template struct foo { static int alloc; };

int main() { return foo::alloc; }

Note that this program, and all of the programs you have posted, have undefined behavior because they don't provide a definition of the static variable.

llvmbot commented 10 years ago

New code, works with -O1 and -O2, shouldn't work, because the uninitialised static member is used.

--- foo.hpp ---

ifndef _FOOHPP

define _FOOHPP

include

template class foo { private: static std::allocator alloc;

T * const payload;

public:
foo(T const val) : payload(foo<T>::alloc.allocate(1)) {
    this->payload[0] = val;
}

virtual ~foo() {
    foo<T>::alloc.deallocate(payload, 1);
}

T const & getPayload() const {
    return this->payload[0];
}

};

endif / _FOOHPP /

--- main.cpp ---

include "foo.hpp"

include

int main() { foo bar(1337); std::cout << &bar.getPayload() << ": " << bar.getPayload() << '\n'; return 0; }

c++ -O2 main.cpp && ./a.out
0x801c06058: 1337 c++ -O1 main.cpp && ./a.out
0x801c06058: 1337 c++ -O0 main.cpp && ./a.out
/tmp/main-e745e6.o: In function foo<int>::foo(int)': main.cpp:(.text._ZN3fooIiEC2Ei[_ZN3fooIiEC2Ei]+0xc): undefined reference tofoo: :alloc' /tmp/main-e745e6.o: In function foo<int>::~foo()': main.cpp:(.text._ZN3fooIiED2Ev[_ZN3fooIiED2Ev]+0xc): undefined reference tofoo: :alloc' c++: error: linker command failed with exit code 1 (use -v to see invocation)

llvmbot commented 10 years ago

I have code where the static member is an std::allocator and I definitely use it.

991901f3-cc14-4404-b340-165691b62a58 commented 10 years ago

You never provide a definition of your static member.

Adding a definition would make your program successfully link:

template T foo::static_member = T();

As to why it works when optimizations are applied: the optimizer realizes you aren't using the 'static_member' variable and optimizes away the references to it.