Allow __cplusplus=199711L to work with Solaris 2 headers
Rainer Orth
ro@CeBiTec.Uni-Bielefeld.DE
Mon Mar 14 20:23:00 GMT 2011
[Please keep me on the Cc: since I'm not subscribed to libstdc++. Thanks.]
Prompted by the recent activity on
libstdc++/1773 __cplusplus defined to 1, should be 199711L
I checked what happens in a Solaris 11/x86 bootstrap if I fix
libcpp/init.c to define __cplusplus correctly as in the following patch:
diff -r f20c297198b4 libcpp/init.c
--- a/libcpp/init.c Sat Mar 12 10:48:29 2011 +0100
+++ b/libcpp/init.c Sat Mar 12 10:51:07 2011 +0100
@@ -452,8 +452,12 @@
|| CPP_OPTION (pfile, std)))
_cpp_define_builtin (pfile, "__STDC__ 1");
- if (CPP_OPTION (pfile, cplusplus))
- _cpp_define_builtin (pfile, "__cplusplus 1");
+ if (CPP_OPTION (pfile, lang) == CLK_CXX98
+ || CPP_OPTION (pfile, lang) == CLK_GNUCXX)
+ _cpp_define_builtin (pfile, "__cplusplus 199711L");
+ else if (CPP_OPTION (pfile, lang) == CLK_CXX0X
+ || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X)
+ _cpp_define_builtin (pfile, "__cplusplus 201103L");
else if (CPP_OPTION (pfile, lang) == CLK_ASM)
_cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
else if (CPP_OPTION (pfile, lang) == CLK_STDC94)
As expected, things broke left and right, but I've now investigated the
failure modes, worked around them (manually for the moment, fixincludes
fixes to follow once the analysis is finished) and managed to get C++
testresults with only four regressions which are due to a g++ bug.
Here's what I found:
The first group of failures were like this (I'm citing the conflicting
definitions immediately below the errors for reference):
In file included from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:42:0:
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cmath: In function 'double std::abs(double)':
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cmath:82:3: error: redefinition of 'double std::abs(double)'
inline double
abs(double __x)
{ return __builtin_fabs(__x); }
/usr/include/iso/math_iso.h:159:16: error: 'double std::abs(double)' previously defined here
inline double abs(double __X) { return fabs(__X); }
There are many more of those. To avoid them, I've changed
<iso/math_iso.h> to read
-#if __cplusplus >= 199711L
+#if __cplusplus >= 199711L && !defined(__GNUG__)
While this certainly works, I'm unclear if the Solaris definition is
actually wrong (I don't think so, but am ignorant of C++). Depending on
the analysis, I'll try to get necessary fixes into Solaris 11, and have
some hope of success since I've got decent contacts into Solaris
engineering. This is one of the reasons for posting this so shortly
after the discussions in the PR.
Next failure:
In file included from /usr/include/stdlib.h:32:0,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cstdlib:66,
from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:48:
/usr/include/iso/stdlib_iso.h: At global scope:
/usr/include/iso/stdlib_iso.h:129:14: error: previous declaration of 'void* std::bsearch(const void*, const void*, std::size_t, std::size_t, int (*)(const void*, const void*))' with 'C' linkage
/usr/include/iso/stdlib_iso.h:134:38: error: conflicts with new declaration with 'C++' linkage
extern void *bsearch(const void *, const void *, size_t, size_t,
int (*)(const void *, const void *));
#if __cplusplus >= 199711L
extern "C++" {
void *bsearch(const void *, const void *, size_t, size_t,
int (*)(const void *, const void *));
}
#endif /* __cplusplus >= 199711L */
One more, can again be avoided by adding && !defined(__GNUG__)
In file included from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:48:0:
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cstdlib: In function 'long int std::abs(long int)':
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cstdlib:139:3: error: redefinition of 'long int std::abs(long int)'
inline long
abs(long __i) { return labs(__i); }
/usr/include/iso/stdlib_iso.h:170:16: error: 'long int std::abs(long int)' previously defined here
#if __cplusplus >= 199711L
extern "C++" {
inline long abs(long _l) { return labs(_l); }
inline ldiv_t div(long _l1, long _l2) { return ldiv(_l1, _l2); }
}
#endif /* __cplusplus */
I don't fully understand the issue: is this due to the redefinition, or
would a redefinition with matching formal parameter names (or without
them) work? (I haven't tried.)
In file included from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:49:0:
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cstring: In function 'void* std::memchr(void*, int, std::size_t)':
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cstring:102:3: error: redefinition of 'void* std::memchr(void*, int, std::size_t)'
inline void*
memchr(void* __s, int __c, size_t __n)
{ return __builtin_memchr(__s, __c, __n); }
/usr/include/iso/string_iso.h:105:15: error: 'void* std::memchr(void*, int, std::size_t)' previously defined here
#ifndef _MEMCHR_INLINE
#define _MEMCHR_INLINE
extern "C++" {
inline void *memchr(void * __s, int __c, size_t __n) {
return (void *)memchr((const void *)__s, __c, __n);
}
}
#endif /* _MEMCHR_INLINE */
Several more, I've added
#define _MEMCHR_INLINE
and similar macros inside a __GNUG__ block.
In file included from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/bits/postypes.h:42:0,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/iosfwd:42,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/ios:39,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/istream:40,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/sstream:39,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/complex:47,
from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/ccomplex:42,
from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:53:
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cwchar: In function 'wchar_t* std::wcschr(wchar_t*, wchar_t)':
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cwchar:214:3: error: redefinition of 'wchar_t* std::wcschr(wchar_t*, wchar_t)'
#ifndef __CORRECT_ISO_CPP_WCHAR_H_PROTO
inline wchar_t*
wcschr(wchar_t* __p, wchar_t __c)
{ return wcschr(const_cast<const wchar_t*>(__p), __c); }
/usr/include/iso/wchar_iso.h:256:18: error: 'wchar_t* std::wcschr(wchar_t*, wchar_t)' previously defined here
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cwchar:215:55: error: invalid conversion from 'const wchar_t*' to 'wchar_t*' [-fpermissive]
extern "C++" {
inline wchar_t *wcschr(wchar_t *__ws, wchar_t __wc) {
return (wchar_t *)wcschr((const wchar_t *)__ws, __wc);
}
}
Several more, same solution.
In file included from /vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cmath:46:0,
from /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/include/precompiled/stdc++.h:42:
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/./gcc/include-fixed/math.h:50:12: error: 'std::abs' has not been declared
<math.h> has
#if __cplusplus >= 199711L
using std::abs;
Again, avoided with !defined(__GNUG__).
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cwchar: In function 'wchar_t* std::wcsstr(wchar_t*, const wchar_t*)':
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cwchar:226:3: error: redefinition of 'wchar_t* std::wcsstr(wchar_t*, const wchar_t*)'
extern "C++" {
inline wchar_t *wcsstr(wchar_t *__ws1, const wchar_t *__ws2) {
return (wchar_t *)wcsstr((const wchar_t *)__ws1, __ws2);
}
}
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/./gcc/include-fixed/iso/wchar_iso.h:340:18: error: 'wchar_t* std::wcsstr(wchar_t*, const wchar_t*)' previously defined here
Same solution again.
/vol/gcc/obj/gcc-4.6.0-20110311/11-gcc-cplusplus/i386-pc-solaris2.11/libstdc++-v3/include/cmath:99:11: error: '::acos' has not been declared
Don't remember any longer what the issue was ;-)
With the fixed headers, libstdc++-v3 configure output changes considerably:
/* Define to 1 if you have the <complex.h> header file. */
-#define HAVE_COMPLEX_H 1
+/* #undef HAVE_COMPLEX_H */
This was due to the following:
In file included from /usr/include/stdio.h:81:0,
from conftest.cpp:34:
/usr/include/iso/stdio_iso.h: In function 'int std::getchar()':
/usr/include/iso/stdio_iso.h:362:41: error: 'getc' was not declared in this scope
/usr/include/iso/stdio_iso.h: In function 'int std::putchar(int)':
/usr/include/iso/stdio_iso.h:363:52: error: 'putc' was not declared in this scope
In file included from conftest.cpp:34:0:
/usr/include/stdio.h: At global scope:
/usr/include/stdio.h:122:12: error: 'std::getc' has not been declared
/usr/include/stdio.h:125:12: error: 'std::putc' has not been declared
For some reason, std::getc, std::putc are declared only if
!_STRICT_STDC, which is defined due to __STRICT_ANSI__. I've hacked
around this again, but suppose this isn't the right solution.
With those changes, I get identical libstdc++ configure output, but the
ABI is broken:
=== libstdc++-v3 check-abi Summary ===
# of added symbols: 76
# of missing symbols: 30
# of incompatible symbols: 60
It turns out that std::time_{get, put}, std::__timepunct are
incompatible, which is due to <iso/time_iso.h>:
> diff -u0 baseline_symbols.txt current_symbols.txt |grep __timepunct|/vol/gcc/bin/c++filt
-FUNC:std::__timepunct<char>::_M_put(char*, unsigned long, char const*, tm const*) const@@GLIBCXX_3.4
+FUNC:std::__timepunct<char>::_M_put(char*, unsigned long, char const*, std::tm const*) const@@GLIBCXX_3.4
-FUNC:std::__timepunct<wchar_t>::_M_put(wchar_t*, unsigned long, wchar_t const*, tm const*) const@@GLIBCXX_3.4
+FUNC:std::__timepunct<wchar_t>::_M_put(wchar_t*, unsigned long, wchar_t const*, std::tm const*) const@@GLIBCXX_3.4
There's a change from tm * to std::tm * here, which I've avoided by
<iso/time_iso.h> hackery.
Afterwards, testsuite results both from make check-g++ and in
libstdc++-v3 are unchanged, with four exceptions:
FAIL: 22_locale/time_put/put/wchar_t/1.cc execution test
Assertion failed: result1 == L"Sun", file /vol/gcc/src/hg/trunk/solaris/libstdc++-v3/testsuite/22_locale/time_put/put/wchar_t/1.cc, line 56, function test01
The same binary works with original libstdc++.so.6.
When the test passes, I find:
(gdb) p result1
$3 = {static npos = <optimized out>,
_M_dataplus = {<std::allocator<wchar_t>> = {<__gnu_cxx::new_allocator<wchar_t>> = {<No data fields>}, <No data fields>},
_M_p = 0x41a0f8 L"S\000\000\000u\000\000\000n\000\000\000"}}
When it fails, I get this instead:
(gdb) p result1
$3 = {static npos = <optimized out>,
_M_dataplus = {<std::allocator<wchar_t>> = {<__gnu_cxx::new_allocator<wchar_t>> = {<No data fields>}, <No data fields>}, _M_p = 0x41a0f8 L"%\000\000\000"}}
config/locale/generic/time_members.cc (wcsftime) returns different results:
* pass:
(gdb) p __s
$15 = 0xfffffd7fffdff1d0 L"S\000\000\000u\000\000\000n\000\000\000"
* fail:
(gdb) p __s
$15 = 0xfffffd7fffdff1f0 L"%\000\000\000"
I found that pass uses __wcsftime_xpg5, fail uses wcsftime. The change
can be reproduced with this testcase:
extern "C" {
namespace std {
#pragma redefine_extname wcsftime __wcsftime_xpg5
struct tm;
typedef unsigned size_t;
extern size_t wcsftime(wchar_t *, size_t, const wchar_t *, const struct tm *);
}
}
using std::wcsftime;
int
main (void)
{
wcsftime (0, 0, 0, 0);
}
If namespace std is present, main actually calls wcsftime, while without
it the call goes to __wcsftime_xpg5. This seems to be a bad interaction
of #pragma redefine_extname and namespaces. With the Sun Studio CC, the
test works as expected.
If this analysis is considered correct, I can file a c++ PR for the
issue.
Just for the record, I'm also including the header patches I made. As
mentioned, they need to be converted to fixincludes hacks if considered
correct, but they will allow others to reproduce my results.
Thanks.
Rainer
--
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: cplusplus-fixincl.udif
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20110314/d40e191c/attachment.ksh>
More information about the Libstdc++
mailing list