Is clang's c++11 support reliable?
Asked Answered
C

1

7

I ran into an interesting issue when trying to mix clang (Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn, Target: x86_64-apple-darwin14.0.0), c++11 and CGAL (via MacPorts).

It seems that whether or not I call std::vector<>::reserve will determine whether my program will even compile.

I've trimmed down the problem into a minimal example (as minimal as CGAL examples get):

#include <vector>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_triangle_primitive.h>

// CGAL::Epeck works fine, suggesting the problem is in CGAL::Epick
typedef CGAL::Epick Kernel;
typedef CGAL::Triangle_3<Kernel> Triangle_3; 
typedef typename std::vector<Triangle_3>::iterator Iterator;
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
typedef CGAL::Point_3<Kernel>    Point_3;

template <typename BKernel>
void A()
{
  const CGAL::AABB_tree<
    CGAL::AABB_traits<BKernel, 
      CGAL::AABB_triangle_primitive<BKernel, 
        typename std::vector<CGAL::Triangle_3<BKernel> >::iterator
      >
    >
  > tree;
  Point_and_primitive_id pp = tree.closest_point_and_primitive(Point_3());
}

void B()
{
  std::vector<Triangle_3> T;
#ifdef MAGIC
  T.reserve(0);
#endif
  return A<Kernel>();
}

Issuing:

clang++ -std=c++11 -c example.cpp -I/opt/local/include

This fails to compile. Giving errors like:

    In file included from example.cpp:1:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:265:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__bit_reference:15:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:626:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/utility:157:
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tuple:228:60: error: 
          no member named 'value' in 'std::__1::is_convertible<const CGAL::Point_3<CGAL::Epick> &,
          CGAL::Point_3<CGAL::Epick> >'
                                   is_convertible<_Tp0, _Up0>::value &&
                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tuple:242:14: note: 
          in instantiation of template class 'std::__1::__tuple_convertible_imp<true, std::__1::__tuple_types<const
          CGAL::Point_3<CGAL::Epick> &, const CGAL::Vector_3<CGAL::Epick> &>,
          std::__1::__tuple_types<CGAL::Point_3<CGAL::Epick>, CGAL::Vector_3<CGAL::Epick> > >' requested here
        : public __tuple_convertible_imp<tuple_size<typename remove_reference<_Tp>::type>::value ==

However, this does compile if I make this magic call to std::vector::reserve, issuing:

clang++ -std=c++11 -c example.cpp -I/opt/local/include -DMAGIC

or by disabling c++11

clang++ -c example.cpp -I/opt/local/include
  1. Is this a bug in CGAL or clang?
  2. What explanation can there be for such erratic compiler behavior?
  3. Is there a clean way of avoiding this (hopefully without really changing the templating or function prototype set up as I need the solution to fit my larger project).
Coom answered 2/1, 2015 at 20:56 Comment(9)
This appears to be a fluke in XCode's definition of is_convertible, but having such a bug is so improbable that my mind refuses to accept it's existence. Do you have any idea which standard library is being used? It's a different one than my clang is using. I don't know what mine is but the top says "Copyright (C) 2001-2013 Free Software Foundation, Inc."Dotted
Clang seems to have libc++, wheras I have libstdc++ en.wikipedia.org/wiki/Standard_Template_Library#ImplementationsDotted
If I add the flag -stdlib=libc++ then the situation does not change. Instead if I add -stdlib=libstdc++ then no version compiles and I get errors like error: no template named 'forward' in namespace 'std';Coom
I'd speculate that your libstdc++ is out-of-date then. I was hoping to check the code to see if I could determine the issue, but you and I have different code. Maybe someone else can study itDotted
You're using a trunk version instead of release? That seems just begging for random errors.Phototype
Using clang (3.4, 3.5 or trunk) with a recent libstdc++ fails in almost exactly the same way while gcc with either libstdc++ or libc++ works.Demogorgon
Note that you should drop typename from the 2 typedefs at the beginning.Demogorgon
llvm.org/bugs/show_bug.cgi?id=22085 hopefully we will soon learn where the bug is.Demogorgon
I still need to check that Richard's analysis carries to the original code (I could have reduced too much), but apparently the bug is in CGAL. Not sure how we are going to fix this, maybe using our own pair class without the C++11 meta-programming checks. As a workaround a "magic" call or typedef or whatever that changes the order in which the classes are instantiated seems like a good strategy...Demogorgon
D
5

Since Apple's GCC is outdated (latest GPL v2 version from 2007, GCC 4.2.1) and not C++11 feature complete (hence the libstdc++ provided with it), you can install a more modern version of GCC through MacPorts (sudo port install gcc48 or sudo port install gcc49) and that will provide you a more modern version of libstdc++. I tested your code with:

/opt/local/bin/g++-mp-4.8 -std=c++11 -c example.cpp -I/opt/local/include

and it compiled succesfully.

If you prefer this solution and want a cleaner compiler call; you can set MacPorts' GCC as the default using gcc_select with the command (in my case for gcc48):

sudo port select --set gcc mp-gcc48

only once. Then, you can compile it with just

g++ -std=c++11 -c example.cpp -I/opt/local/include

in a new terminal session.

Duroc answered 2/1, 2015 at 22:0 Comment(4)
Thanks for the explanation. This was my typical set up, but my goal now is to get my project to compile with the built in clang on mac: so I don't want to switch compilers. Which feature of C++11 is missing this example?Coom
Thank you. Looking at your comments in the question, it looks like std::forward is missing when you use Apple's libstdc++. The long (but hopefully rewarding) way will be to ignore MacPorts and compiling CGAL and all its dependencies yourself with built-in clang. I never did this myself and I would be interested to read about your experience if you do it. An alternative might be reporting these issues to MacPorts' maintainers and wait for them to change the compilation scripts of CGAL and its dependendencies.Duroc
Thanks. So, in the end is this a bug in CGAL or a bug in Apple's libstdc++ which CGAL is somehow stumbling upon?Coom
I would say it is either "a problem" with MacPorts not compiling CGAL and all its dependencies with Apple's clang and libc++ or with Apple's libstdc++ being too old (which is not exactly a bug but a license issue related to the newer versions of libstdc++ being licensed with GPLv3 and the restrictions in GPLv3 preventing Apple from including it with the OS X).Duroc

© 2022 - 2024 — McMap. All rights reserved.