[Bug c++/52069] New: ARM: initialization of static member in template struct

2012-01-31 Thread thomas.bet...@rohde-schwarz.com
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52069

 Bug #: 52069
   Summary: ARM: initialization of static member in template
struct
Classification: Unclassified
   Product: gcc
   Version: 4.5.3
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
AssignedTo: unassig...@gcc.gnu.org
ReportedBy: thomas.bet...@rohde-schwarz.com


main.cpp is linked with a shared library libtmpl.so which initializes a static
member S::id of a template struct. The expected outcome is that main() sees
the initialized value of S::id. When tmpl.cpp is compiled with optimization,
though, the actual outcome is that main() sees an all-zeros value.

The problem was observed with gcc-4.5.2, gcc-4.5.3, gcc-4.6.0, gcc-4.6.1, all
built by crosstool-ng-1.13.2 for ARM (gcc-4.6.2 is not yet supported by
crosstool-ng); the output of g++ -v for gcc-4.5.3 is included at the end of
this text. I was not able to reproduce the problem for x86.

The attached .tgz contains tmpl.h, tmpl.cpp, main.cpp as well as tmpl.ii,
main.ii. I have compiled main.cpp and tmpl.cpp as follows:

arm-armv6-linux-gnueabi-g++ -c -o main.o main.cpp
arm-armv6-linux-gnueabi-g++ -c -O -o tmpl.o tmpl.cpp
arm-armv6-linux-gnueabi-g++ -shared -Wl,-soname,libtmpl.so -o libtmpl.so tmpl.o
arm-armv6-linux-gnueabi-g++ -o testbug main.o libtmpl.so

I did the usual checks with -Wall -Wextra; there were no warnings or errors.

The example is minimal in the sense that the problem does not occur when:
* tmpl.cpp is compiled without optimization (it does not matter if main.cpp is
compiled with or without optimization)
* main.o is linked directly with tmpl.o, i.e., you cannot skip the shared
library step
* S::id is initialized by an immediate value, not by a separate const
* S::id is an unsigned long, not a struct

The problem also does not occur when you add a line "template struct S;"
before the initialization; this is our current workaround. I can't tell if this
explicit instantiation is permitted or even required by the standard [I leave
this question to the C++ gurus], but g++ does not complain either way, and at
least it helps ...

My impression from debugging was that the initialization is not correctly
relocated. The symbol S::id exists twice, once in the BSS section of
libtmpl.so and once in the BSS section of main.o; without optimization, the
symbol in main.o is initialized (as it should), and with optimization, the
symbol in libtmpl.so is initialized. But that's just my 2ยข.

The output of arm-armv6-linux-gnueabi-g++ -v is:

Using built-in specs.
COLLECT_GCC=/home/RSINT/betker/opt/arm-4.5.3/bin/arm-armv6-linux-gnueabi-g++
COLLECT_LTO_WRAPPER=/home/RSINT/betker/opt/arm-4.5.3/bin/../libexec/gcc/arm-armv6-linux-gnueabi/4.5.3/lto-wrapper
Target: arm-armv6-linux-gnueabi
Configured with:
/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/src/gcc-4.5.3/configure
--build=i686-build_pc-linux-gnu --host=i686-build_pc-linux-gnu
--target=arm-armv6-linux-gnueabi --prefix=/home/RSINT/betker/opt/arm-5.4.3
--with-sysroot=/home/RSINT/betker/opt/arm-5.4.3/arm-armv6-linux-gnueabi/sysroot
--enable-languages=c,c++ --disable-multilib --with-arch=armv6 --with-fpu=vfp3
--with-pkgversion='crosstool-NG 1.13.2' --enable-__cxa_atexit
--disable-libmudflap --disable-libgomp --disable-libssp
--with-gmp=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-mpfr=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-mpc=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-ppl=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-cloog=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-libelf=/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static
--with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++ -lm
-L/home/RSINT/betker/tmp/crosstool-ng-1.13.2-arm-5.4.3/.build/arm-armv6-linux-gnueabi/build/static/lib
-lpwl' --enable-threads=posix --enable-gold
--with-local-prefix=/home/RSINT/betker/opt/arm-5.4.3/arm-armv6-linux-gnueabi/sysroot
--disable-nls --enable-c99 --enable-long-long
Thread model: posix
gcc version 4.5.3 (crosstool-NG 1.13.2)


[Bug c++/52069] ARM: initialization of static member in template struct

2012-01-31 Thread thomas.bet...@rohde-schwarz.com
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52069

--- Comment #1 from Thomas Betker  2012-01-31 
15:07:42 UTC ---
Created attachment 26536
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=26536
bug test source files


[Bug c++/52069] ARM: initialization of static member in template struct

2012-01-31 Thread thomas.bet...@rohde-schwarz.com
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52069

--- Comment #5 from Thomas Betker  2012-01-31 
16:25:02 UTC ---
Okay, got it; thanks a lot for the ultra-quick reply!

Wouldn't a diagnostic message be helpful here even if it is not required by the
standard? After all, the resulting binaries won't work correctly.

I also keep wondering why things do work when optimization is disabled, but I
guess the compiler may do anything it pleases since the input is invalid.


[Bug c++/52069] ARM: initialization of static member in template struct

2012-02-01 Thread thomas.bet...@rohde-schwarz.com
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52069

--- Comment #8 from Thomas Betker  2012-02-01 
10:51:58 UTC ---
> There's a reason the standard says "no diagnostic required."
> 
> When compiling libtmpl.so, how is the compiler supposed to know that a
> different translation unit which it can't see (and which might not even have
> been written yet) will implicitly instantiate the member?  When compiling
> main.o, how is the compiler supposed to know that an explicit specialization
> exists in a separate translation unit which it can't see?

Okay. So if I read the quote correctly, the standard does not require explicit
specialization, it just requires that an explicit specialization, if present,
is declared before any implicit instantiation. This explains why no there is no
warning if the explicit specialization is missing.

However, this also means that the test case does not violate the quoted rule
because there is simply no explicit specialization at all. I am quite willing
to believe that it is ill-formed, but the reason lies probably in the rules for
implicit specialization; I will have to read up on this.

> With optimisation enabled the compilation of main.o probably removes condition
> because the constant is known to be zero because there has been no explicit
> specialization declared. Without optimisation a weak symbol is emitted, which
> may or may not be replaced by the weak symbol in libtmpl.so that has a
> different value.

objdump says that the symbol S::id both in testbug and in libtmpl.so (with
and without optimization) is a global, strong object in .bss; the symbol
(exists and) is undefined in main.o. 

Without optimization, S::id is initialized in libtmpl.so by
__static_initialization_and_destruction_0(int, int) [which is called by
'::id']. When run on the target, the function
is relocated to point to the object in testbug (i did a disassembly in gdb). So
in some sense, it S::id in libtmpl.so is indeed treated as a weak object.

With optimization, S::id is initialized in libtmpl.so directly by 'global
constructors keyed to S::id'. When run on the target, the function still
points to the object in libtmpl.so, which no longer seems to be weak. 

I am afraid that this inconsistency still bothers me, apart from the fact that
I couldn't reproduce the problem for x86.

When the explicit specialization is added in tmpl.h, or just in tmpl.cpp, the
symbol S::id both in testbug and in libtmpl.so (with optimization) is a
global, weak object in .bss.