Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Jan 2016 23:05:00 -0800
From:      Mark Millard <markmi@dsl-only.net>
To:        Dimitry Andric <dim@FreeBSD.org>
Cc:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Toolchain <freebsd-toolchain@freebsd.org>
Subject:   Re: powerpc64-gcc unable to compile clang 3.8.0 from clang380-import -r294609 via buildworld
Message-ID:  <EE2741F6-406D-4D93-8DF6-91B788F99182@dsl-only.net>
In-Reply-To: <582B67B0-25F4-40BE-A92F-D4818DCB9F97@dsl-only.net>
References:  <67523280-9F20-4638-BF24-1BFAE8583805@dsl-only.net> <5B511209-F26D-4788-B80B-E0328963C263@FreeBSD.org> <582B67B0-25F4-40BE-A92F-D4818DCB9F97@dsl-only.net>

next in thread | previous in thread | raw e-mail | index | archive | help
Modern boost (1.60.0) deals with the __GXX_EXPERIMENTAL_CXX0X__ =
(-std=3Dc++0x) vs. -std=3Dc++11 issue this way in its =
config/compiler/gcc.hpp :

> #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >=3D 201103L)
> #  define BOOST_GCC_CXX11
> #endif

then later checking BOOST_GCC_CXX11 (and other things) as needed instead =
of directly testing __GXX_EXPERIMENTAL_CXX0X__ in those places.=20

This started in boost 1.57.0 (2014-Nov-3) when the then-most-recent gcc =
"primary test compilers" for C++ language vintages were all gcc 4.9.1 =
and the most recent for "additional test compilers" for GCC C++11/14 =
were also 4.9.1 --other than Linux where "5.0 (experimental)" is listed =
in the release notes but not for GCC with C++11/14.


Should libc++ should be doing something similar that takes into account =
when C++xy features are no longer experimental in g++?


=3D=3D=3D
Mark Millard
markmi at dsl-only.net

On 2016-Jan-23, at 10:17 PM, Mark Millard <markmi at dsl-only.net> =
wrote:

I found a (the?) overall smoking gun: for powerpc64-gcc FreeBSD's =
/projects/clang380-import/contrib/libc++/include/__config is doing (for =
example):

#define _LIBCPP_HAS_NO_RVALUE_REFERENCES

(and other out of date classifications) for gcc5 vintages, and possibly =
for gcc49 and others as well.

This in turn means that other parts of libc++ are not providing modern =
definitions that modern enough gcc5 variations handle fine. Instead =
libc++ provides old definitions that are incorrect/incomplete for c++11 =
and later (despite use of -std=3Dc++11 on the command line).

clang++ gets the modern definitions from libc++.

So: Not a gcc problem, a libc++ problem.


In the code that got the initial error report that I showed =
/projects/clang380-import/contrib/libc++/include/__config was using old =
definitions of std::begin(. . .) and std::end(. . .) for powerpc64-gcc =
and when the modern definitions are used instead under powerpc64-gcc the =
matching error report disappears.


Part of this may be that __config is still always expecting for g++ that =
__GXX_EXPERIMENTAL_CXX0X__ is defined if nearly any of the modern c++11 =
or later features exist at all. At this point various things are not =
experimental any more and -std=3Dc++11 features likely are not =
considered experimental any more in more recent gcc5 and later vintages.

This __GXX_EXPERIMENTAL_CXX0X__ use is still true of __config at llvm's =
/libcxx/tags/RELEASE_380/rc1/include/__config and at llvm's =
/libcxx/trunk/include/__config too (head of trunk for the file).


Looking at the most recent content of FreeBSD's =
/projects/clang380-import/contrib/libc++/include/__config shows:

. . .
#elif defined(__GNUC__)
. . .
. . .
// GCC 5 will support variable templates
#define _LIBCPP_HAS_NO_VARIABLE_TEMPLATES
. . .
#ifndef __GXX_EXPERIMENTAL_CXX0X__
. . .
#define _LIBCPP_HAS_NO_RVALUE_REFERENCES
. . .
#else  // __GXX_EXPERIMENTAL_CXX0X__
. . .
#if _GNUC_VER < 403
#define _LIBCPP_HAS_NO_RVALUE_REFERENCES
#endif
. . .

_LIBCPP_HAS_NO_RVALUE_REFERENCES being defined in turn causes =
/projects/clang380-import/contrib/libc++/include/iterator to define =
things like std::begin(. . .) in an old way, such as the following that =
was involved in the initial error report that I got:

> #else  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && =
!defined(_LIBCPP_HAS_NO_TRAILING_RETURN)
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::iterator
> begin(_Cp& __c)
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::const_iterator
> begin(const _Cp& __c)
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::iterator
> end(_Cp& __c)
> {
>    return __c.end();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::const_iterator
> end(const _Cp& __c)
> {
>    return __c.end();
> }


Manually forced replacement with modern source:

> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> begin(_Cp& __c) -> decltype(__c.begin())
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> begin(const _Cp& __c) -> decltype(__c.begin())
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> end(_Cp& __c) -> decltype(__c.end())
> {
>    return __c.end();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> end(const _Cp& __c) -> decltype(__c.end())
> {
>    return __c.end();
> }

eliminated the specific initial error report. (It is not a sufficient =
workaround to build clang as far as I know.)

The following code extracted from libc++ and simplified from the llvm =
code that got the initial error that I showed can be used to experiment =
with the definitions of std::begin(. . .) and std:end(. . .) for =
powerpc64-gcc vs. clang++ via commands like:

> /usr/local/bin/powerpc64-portbld-freebsd11.0-g++ -std=3Dc++11 =
-I/usr/include/c++/v1/ func.cpp

vs.

> clang++ -std=3Dc++11 -stdlib=3Dlibc++ func.cpp


with func.cpp being . . .
(llvm's head-of-trunk iterator still has the same #if . . . #else . . . =
#endif structure)

> #include <__config>
>=20
> _LIBCPP_BEGIN_NAMESPACE_STD
>=20
> #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && =
!defined(_LIBCPP_HAS_NO_TRAILING_RETURN)
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> begin(_Cp& __c) -> decltype(__c.begin())
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> begin(const _Cp& __c) -> decltype(__c.begin())
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> end(_Cp& __c) -> decltype(__c.end())
> {
>    return __c.end();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> auto
> end(const _Cp& __c) -> decltype(__c.end())
> {
>    return __c.end();
> }
>=20
> #else  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && =
!defined(_LIBCPP_HAS_NO_TRAILING_RETURN)
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::iterator
> begin(_Cp& __c)
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::const_iterator
> begin(const _Cp& __c)
> {
>    return __c.begin();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::iterator
> end(_Cp& __c)
> {
>    return __c.end();
> }
>=20
> template <class _Cp>
> inline _LIBCPP_INLINE_VISIBILITY
> typename _Cp::const_iterator
> end(const _Cp& __c)
> {
>    return __c.end();
> }
>=20
> #endif  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && =
!defined(_LIBCPP_HAS_NO_TRAILING_RETURN)
>=20
> _LIBCPP_END_NAMESPACE_STD
>=20
> namespace ns {
>  template <typename IteratorT>
>  class iterator_range {
>    IteratorT begin_iterator, end_iterator;
>=20
>  public:
>    iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
>        : begin_iterator(begin_iterator),
>          end_iterator(end_iterator) {}
>=20
>    IteratorT begin() const { return begin_iterator; }
>    IteratorT end() const { return end_iterator; }
>  };
>=20
>  template <class T> iterator_range<T> make_range(T x, T y) {
>    return iterator_range<T>(x, y);
>  }
>=20
>  template <typename ContainerTy>
>  auto test( ContainerTy &&C
>              ) -> decltype(make_range(std::begin(C),
>                                       std::end(C))) {
>    return make_range(std::begin(C),
>                      std::end(C));
>  }
> };
>=20
> typedef int *const init_const_ptr;
> typedef int *const *init_const_iterator;
>=20
> int                 v;
> init_const_ptr      cvp =3D &v;
> init_const_iterator pcpv =3D &cvp;
>=20
> typedef ns::iterator_range<init_const_iterator> init_const_range;
>=20
> void f(void) {
>    for (auto *I : ns::test(init_const_range(pcpv,pcpv+1))) {
>    }
> }
>=20
> int main(void)
> { return 0; }

Commenting out inside one branch of the #if . . . #else . . . #endif =
makes very clear if that part was in use or the other part. Switching =
compilers switches which part is used in my testing.



It also appears that =
/projects/clang380-import/contrib/libc++/include/__config has not been =
tracking various 3.8.0 changes. For example llvm's Log of =
/libcxx/tags/RELEASE_380/rc1/include/__config shows that its 2015-Dec-14 =
-r255585  version changed the _LIBCPP_HAS_NO_VARIABLE_TEMPLATES source =
that I quoted earlier to instead be:

> // GCC 5 will support variable templates
> #if !defined(__cpp_variable_templates) || __cpp_variable_templates < =
201304L
> #define _LIBCPP_HAS_NO_VARIABLE_TEMPLATES
> #endif


(increasing the support for modern g++'s a little bit).

llvm's /libcxx/tags/RELEASE_380/rc1/include/__config is currently at =
-r258234 (2016-Jan-19) with about 8 checkins between the 2 versions.

Looking up /projects/clang380-import/contrib/libc++/include/iterator and =
others show they date back being copies made on 2015-Dec-30 of vintages =
from FreeBSD's 2015-Oct 3.7.0 materials as well. (For some files that =
may well be current for all I know.)

For all I know this status is deliberate for some reason. But it would =
seem that to expect modern gcc vintages to be supported well for modern =
libc++ uses probably has a necessary (but not sufficient) aspect of =
tracking llvm's updates that add handling of more modern gcc vintages.


Side note:

One revision in llvm's /libcxx/tags/RELEASE_380/rc1/include/ that I ran =
into that might be of note: -r257716 from 2016-Jan-13 says

> Fix PR#25973 : 'basic_string::assign(InputIt, InputIt) doesn't provide =
the strong exception safety guarantee'. This turned out to be a =
pervasive problem in <string>, which required a fair amount of rework. =
Add in an optimization for when iterators provide noexcept =
increment/comparison/assignment/dereference (which covers many of the =
iterators in libc++).




=3D=3D=3D
Mark Millard
markmi at dsl-only.net

On 2016-Jan-23, at 7:08 AM, Dimitry Andric <dim@FreeBSD.org> wrote:

On 23 Jan 2016, at 12:25, Mark Millard <markmi@dsl-only.net> wrote:
>=20
> I tried a buildworld that included building clang and lldb based on =
using powerpc64-xtoolchain-gcc/powerpc64-gcc as a cross compiler. It =
failed, see below. This might indicate a more general gcc 5.x vs. clang =
3.8.0 source code mismatch. This was my first try. This could have been =
true for some time.
>=20
> --- CFG.o ---
> /usr/local/bin/powerpc64-portbld-freebsd11.0-g++ -isystem =
/usr/obj/xtoolchain/powerpc.powerpc64/usr/src/tmp/usr/include =
-L/usr/obj/xtoolchain/powerpc.powerpc64/usr/src/tmp/usr/lib =
--sysroot=3D/usr/obj/xtoolchain/powerpc.po
> werpc64/usr/src/tmp -B/usr/local/powerpc64-freebsd/bin/ =
-I/usr/obj/xtoolchain/powerpc.powerpc64/usr/src/tmp/usr/include/c++/v1 =
-std=3Dgnu++11 =
-L/usr/obj/xtoolchain/powerpc.powerpc64/usr/src/tmp/../lib/libc++ =
--sysroot=3D/usr
> /obj/xtoolchain/powerpc.powerpc64/usr/src/tmp =
-B/usr/local/powerpc64-freebsd/bin/  -O2 -pipe =
-I/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/include =
-I/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm
> /tools/clang/include =
-I/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/tools/clang/li=
b/Analysis -I. =
-I/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/../../lib/clan=
g/include -DLLVM_ON_UNIX -DLLVM_ON_FREEBSD -D__STDC_LIMIT_MACROS =
-D__STDC_CONSTANT_MACROS -DCLANG_ENABLE_ARCMT =
-DCLANG_ENABLE_STATIC_ANALYZER -fno-strict-aliasing =
-DLLVM_DEFAULT_TARGET_TRIPLE=3D\"powerpc64-unknown-freebsd11.0\" =
-DLLVM_HOST_TRIPLE=3D\"powerpc64
> -unknown-freebsd11.0\" -DDEFAULT_SYSROOT=3D\"\" -MD -MP =
-MF.depend.CFG.o -MTCFG.o -fstack-protector-strong =
-Wno-error=3Dunused-function -Wno-error=3Denum-compare =
-Wno-error=3Dlogical-not-parentheses -Wno-error=3Dbool-compare -Wno-
> error=3Duninitialized -Wno-error=3Darray-bounds -Wno-error=3Dclobbered =
-Wno-error=3Dcast-align -Wno-error=3Dextra -Wno-error=3Dattributes =
-Wno-error=3Dinline -Wno-error=3Dunused-but-set-variable =
-Wno-error=3Dunused-value -Wno-error=3Dstrict
> -aliasing -Wno-error=3Daddress  -std=3Dc++11 -fno-exceptions -fno-rtti =
 -c =
/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/tools/clang/lib/=
Analysis/CFG.cpp -o CFG.o
> . . .
> --- all_subdir_libclanganalysis ---
> =
/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/tools/clang/lib/=
Analysis/CFG.cpp: In member function 'std::__1::unique_ptr<clang::CFG> =
{anonymous}::CFGBuilder::buildCFG(const clang::Decl*, clang::Stmt*)':
> =
/usr/src/lib/clang/libclanganalysis/../../../contrib/llvm/tools/clang/lib/=
Analysis/CFG.cpp:1046:45: error: no matching function for call to =
'reverse(clang::CXXConstructorDecl::init_const_range)'
>   for (auto *I : llvm::reverse(CD->inits())) {
>                                           ^

I just tried building clang 3.8.0 with gcc 5.3.0, but that went fine.
However, by default gcc uses its own copy of libstdc++.  The above error
is most likely something caused by libc++ and gcc not playing well
together.

This kind of error is always hard to report upstream, since the gcc
maintainers obviously do not care that much about libc++, while the
libc++ maintainers do not care that much about gcc. :-)

-Dimitry






Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?EE2741F6-406D-4D93-8DF6-91B788F99182>