Bug 52765 - -std=c++0x requires multilib for non-optimized libstdc++
Summary: -std=c++0x requires multilib for non-optimized libstdc++
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.6.3
: P3 normal
Target Milestone: 4.8.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-03-29 09:11 UTC by christophe.lyon
Modified: 2024-01-17 11:47 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-03-29 00:00:00


Attachments
Very lightly tested so far (262 bytes, patch)
2012-03-29 13:23 UTC, Paolo Carlini
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description christophe.lyon 2012-03-29 09:11:53 UTC
Hello,
While experimenting with -std=c++0x and libstdc++ built at -O0 [1], I noticed that this sample code does not produce the expected result:
==================8<>===============
#include <iostream>
#include <complex>

int main()
{
    const std::complex<float> cf (23., 101.);

    std::cout << cf.real() << '\n';
    std::cout << cf << '\n';

    return 0;
}
==================8<>===============
That is, with -std=c++0x it prints:
23
(0,101)
and without -std=c++0x it prints:
23
(23,101)

This is because the call to cf.real() makes the compiler generate a 'c++0x' variant of std::complex<float>::real() const, which is also called implicitly by the library when printing the complex. But the library expects the non 'c++0x' version.

Admittedly, libstdc++ seems to be expected to compiled at -O2 and thus std::complex<float>::real() is normally inlined, but I am wondering whether there might be other functions in libstdc++ which would not be inlined at -O2 in the library itself, and thus subject to the same problem.

One way of having compliant libraries for me is to use multilib, but understanding the root cause of such errors might not be easy for the average user.

I am not sure this is really a bug (is building libstdc++ at -O0 supported?), but at least I think it might be worth checking that other functions whose prototype changes with -std=c++0x are always inlined in the library itself.



[1] I built libstdc++ at -O0 inadvertently, by overriding CFLAGS (not including -O2) before building GCC.
Comment 1 christophe.lyon 2012-03-29 09:19:30 UTC
If you look at libstdc++-v3/include/std/complex:
[...]
#ifdef __GXX_EXPERIMENTAL_CXX0X__
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // DR 387. std::complex over-encapsulated.
      constexpr _Tp
      real() const { return _M_real; }
[...]
#else
[...]
      ///  Return real part of complex number.
      const _Tp&
      real() const { return _M_real; }
[...]
#endif

You can see that depending of __GXX_EXPERIMENTAL_CXX0X__ (automatically defined with -std=c++0x), the type of the value returned by real() is different.
Comment 2 Jonathan Wakely 2012-03-29 10:08:20 UTC
(In reply to comment #0)
> I am not sure this is really a bug (is building libstdc++ at -O0 supported?),

Yes, the --enable-libstdcxx-debug configure option builds an alternative libstdc++.so with -O0 (but I can't reproduce this when using that lib)
Comment 3 christophe.lyon 2012-03-29 12:08:43 UTC
Not sure how/if it matters: I am looking at a cross gcc for arm-none-eabi, built with --disable-shared.
Comment 4 Paolo Carlini 2012-03-29 13:12:40 UTC
Something seems fishy on x86_64-linux too, with the library built -O0 and -std=c++11 I see random segfaults.

But since the problem seems simply that at -O0 we have these *additional* unwanted exports:

000000000008031e W std::complex<double>::imag() const
0000000000080310 W std::complex<double>::real() const
0000000000080394 W std::complex<long double>::imag() const
0000000000080386 W std::complex<long double>::real() const
00000000000802ac W std::complex<float>::imag() const
000000000008029e W std::complex<float>::real() const
00000000000802e4 W std::complex<double>::complex(double, double)
00000000000802e4 W std::complex<double>::complex(double, double)
0000000000080330 W std::complex<double>::operator=(double)
0000000000080358 W std::complex<long double>::complex(long double, long double)
0000000000080358 W std::complex<long double>::complex(long double, long double)
00000000000803a6 W std::complex<long double>::operator=(long double)
0000000000080276 W std::complex<float>::complex(float, float)
0000000000080276 W std::complex<float>::complex(float, float)
00000000000802be W std::complex<float>::operator=(float)

I suppose the fix should be straightforward: just tighten the linker map and prevent that from happening.
Comment 5 Paolo Carlini 2012-03-29 13:13:19 UTC
linker script, I meant
Comment 6 Paolo Carlini 2012-03-29 13:23:17 UTC
Created attachment 27033 [details]
Very lightly tested so far

Appears to work as expected. Maybe submitter can test it in his config: just apply the patchlet and rebuild (library only is fine) as usual.
Comment 7 christophe.lyon 2012-03-29 15:45:42 UTC
It doesn't work in my context:
- symbol versioning does not apply to static libraries (as already said, I'm using --disable-shared)
- the problem is not that the library is exporting unwanted symbols, but that it is referencing symbols which happen to be defined in the user main.o with a different prototype.

main.o defines and calls real()
libstdc++.a (complex_io.o) calls real(), but expects the version defined in libstdc++.a which has a different prototype from the one in main.o. However, it uses the version in main.o by link rules.

Another possible fix could be to add the always_inline attribute in the library, or make sure to distinguish both prototypes.
Comment 8 Paolo Carlini 2012-03-29 15:52:52 UTC
For sure, anyway, at -O0 the library *is* exporting unwanted symbols. I'm not sure that at this time we can really support what you want.
Comment 9 christophe.lyon 2012-03-30 08:39:19 UTC
(In reply to comment #2)
> (In reply to comment #0)
> > I am not sure this is really a bug (is building libstdc++ at -O0 supported?),
> 
> Yes, the --enable-libstdcxx-debug configure option builds an alternative
> libstdc++.so with -O0 (but I can't reproduce this when using that lib)

I have experimented with this configure option. I didn't know about it: what is the intended way of using the debug libraries? I have add -L..../debug to my link command, and I do reproduce the problem in this context:
- target arm-none-eabi
- --disable-shared

# Using default libs, built at -O2
$ arm-none-eabi-g++ cplx.cxx -o cplx.u -mcpu=cortex-a9 -std=c++0x
$ qemu-system-arm -semihosting -cpu cortex-a9 -nographic -kernel ./cplx.u
23
(23,101)

# Using debug libs, built at -O0
$ arm-none-eabi-g++ cplx.cxx -o cplx.u -mcpu=cortex-a9 -std=c++0x -L .../lib/debug
$ qemu-system-arm -semihosting -cpu cortex-a9 -nographic -kernel ./cplx.u
23
(0,101)
Comment 10 Jonathan Wakely 2012-03-30 09:59:51 UTC
(In reply to comment #9)
> I have experimented with this configure option. I didn't know about it: what is
> the intended way of using the debug libraries?

I use debug/libstdc++.so via LD_LIBRARY_PATH when I want to run in gdb and step-through code in the library. i.e. I link as normal, but switch to using the debug lib at run-time. Obviously if using static linking that doesn't work so you'd have to decide to use that lib at link-time.

I mentioned it here because it's a common (and supported) way to get a libstdc++ built with -O0 while keeping the primary libs built with the usual flags (-O2 etc.)
Comment 11 christophe.lyon 2012-06-25 14:38:00 UTC
I have proposed a patch related to this problem some time ago, which received no feedback:
http://gcc.gnu.org/ml/gcc-patches/2012-03/msg01855.html
Comment 12 Jonathan Wakely 2012-06-25 14:45:18 UTC
Patches for libstdc++ should be sent to the libstdc++ list as well as gcc-patches. That's probably why you didn't get any feedback.
Comment 13 Jonathan Wakely 2012-06-25 14:50:10 UTC
Oh I see it isn't specific to libstdc++.  You'll just have to push on the gcc-patches list for review then.  It helps if you describe the problem it solves in detail, and confirm it was tested successfully, stating on which platform(s).
Comment 14 Jonathan Wakely 2017-01-18 17:36:17 UTC
The original problem should be fixed long ago, because those functions use the abi_tag now.
Comment 15 Jonathan Wakely 2024-01-17 11:47:21 UTC
(In reply to Jonathan Wakely from comment #14)
> The original problem should be fixed long ago, because those functions use
> the abi_tag now.

I think this was fixed for gcc 4.8.0 by r0-120238-g7a3a9e6821ff5e so I'm going to close it.