Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Failure to compile Boost.Python #12833

Open Quuxplusone opened 12 years ago

Quuxplusone commented 12 years ago
Bugzilla Link PR12727
Status NEW
Importance P normal
Reported by Luc Bourhis (luc_j_bourhis@mac.com)
Reported on 2012-05-02 11:40:59 -0700
Last modified on 2012-05-05 21:58:08 -0700
Version trunk
Hardware PC All
CC dgregor@apple.com, efriedma@quicinc.com, llvm-bugs@lists.llvm.org, mimomorin@gmail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
clang++ fails to compile the preprocessed source available here (too big to
attach, hence that link):
http://80.11.252.214/~luc/wrapper.cpp

In case it helps, I bisected Boost to find the Boost commit which broke it (as
I discovered that problem by updating my Boost repository): it is rev 77146,

Author: johnmaddock <johnmaddock@b8fc166d-592f-0410-95f2-cb63ce0dd405>
Date:   Thu Mar 1 11:27:18 2012 +0000

    Apply Clang patch from Michel Morin.

and its diff is as follow

diff --git a/boost/type_traits/intrinsics.hpp b/boost/type_traits/intrinsics.hpp
index d47b33e..e5c25d3 100644
--- a/boost/type_traits/intrinsics.hpp
+++ b/boost/type_traits/intrinsics.hpp
@@ -131,10 +131,10 @@
 #   if __has_feature(is_union)
 #     define BOOST_IS_UNION(T) __is_union(T)
 #   endif
-#   if __has_feature(is_pod) && defined(_LIBCPP_VERSION)
+#   if (__has_feature(is_pod) && defined(_LIBCPP_VERSION)) ||
__has_feature(__is_pod__)
 #     define BOOST_IS_POD(T) __is_pod(T)
 #   endif
-#   if __has_feature(is_empty) && defined(_LIBCPP_VERSION)
+#   if (__has_feature(is_empty) && defined(_LIBCPP_VERSION)) ||
__has_feature(__is_empty__)
 #     define BOOST_IS_EMPTY(T) __is_empty(T)
 #   endif
 #   if __has_feature(has_trivial_constructor)

Finally, here are the errors reported by clang++

~> clang++ -c wrapper.cpp
In file included from
/Users/luc/Developer/cctbx/boost/libs/python/src/wrapper.cpp:1:
In file included from
/Users/luc/Developer/cctbx/boost/libs/python/src/wrapper.cpp:5:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/wrapper.hpp:8:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/override.hpp:11:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/converter/return_from_python.hpp:12:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/converter/object_manager.hpp:8:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/handle.hpp:11:
In file included from
/Users/luc/Developer/cctbx/boost/boost/python/errors.hpp:13:
In file included from
/Users/luc/Developer/cctbx/boost/boost/function/function0.hpp:11:
In file included from
/Users/luc/Developer/cctbx/boost/boost/function/detail/maybe_include.hpp:13:
In file included from
/Users/luc/Developer/cctbx/boost/boost/function/function_template.hpp:13:
In file included from
/Users/luc/Developer/cctbx/boost/boost/function/detail/prologue.hpp:17:
In file included from
/Users/luc/Developer/cctbx/boost/boost/function/function_base.hpp:22:
In file included from
/Users/luc/Developer/cctbx/boost/boost/type_traits/has_trivial_copy.hpp:15:
/Users/luc/Developer/cctbx/boost/boost/type_traits/is_pod.hpp:40:129: error:
'T' does not refer to a
      value
  ...::boost::is_scalar<T>::value, ::boost::is_void<T>::value, __is_pod(T) >::value);
                                                                        ^
/Users/luc/Developer/cctbx/boost/boost/type_traits/is_pod.hpp:38:20: note:
declared here
template <typename T> struct is_pod_impl
                   ^
/Users/luc/Developer/cctbx/boost/boost/type_traits/is_pod.hpp:40:135: error:
type name requires a
      specifier or qualifier
  ...::boost::is_scalar<T>::value, ::boost::is_void<T>::value, __is_pod(T) >::value);
                                                                              ^
/Users/luc/Developer/cctbx/boost/boost/type_traits/is_pod.hpp:40:135: error:
expected ')'
/Users/luc/Developer/cctbx/boost/boost/type_traits/is_pod.hpp:40:31: note: to
match this '('
    static const bool value = (::boost::type_traits::ice_or< ::boost::is_scalar<T>::value,...
                              ^
3 errors generated.
Quuxplusone commented 12 years ago

Thanks Luc for pointing this out. My intention of the change to Boost.TypeTraits

-# if has_feature(is_pod) && defined(_LIBCPP_VERSION) +# if (has_feature(is_pod) && defined(_LIBCPP_VERSION)) || has_feature(__is_pod)

was to allow the use of clang's __is_pod type traits intrinsic when used with libstdc++ newer than 4.2. But it seems that this introduces some subtlety when used with libstdc++ 4.2.

Here is a minimal code which fails to compile with libstdc++ 4.2.

#if __has_feature(__is_pod__)
#  define MY_IS_POD(T) __is_pod(T)
#else
#  define MY_IS_POD(T) false
#endif

// The following include brings libstdc++'s `struct __is_pod`;
// this turns off clang's `__is_pod` type traits intrinsic. 
#include <iostream>

template <typename T>
struct my_is_pod
{
    // Here, clang's `__is_pod` type traits intrinsic is turned off;
    // `__is_pod` is considered as libstdc++'s `struct __is_pod`. 
    static const bool value = MY_IS_POD(T);
};

int main (int argc, char* argv[])
{
    std::cout << my_is_pod<int>::value << std::endl; // --> error

    return 0;
}

The problem in the code is that detection of __is_pod intrinsics is done before libstdc++'s struct __is_pod is introduced, but the use of __is_pod intrinsics is done after libstdc++'s struct __is_pod is introduced.

The following two variants of the codes compile fine with libstdc++ 4.2.

A.

include

#if __has_feature(__is_pod__)
#  define MY_IS_POD(T) __is_pod(T)
#else
#  define MY_IS_POD(T) false
#endif

template <typename T>
struct my_is_pod
{
    static const bool value = MY_IS_POD(T);
};

int main (int argc, char* argv[])
{
    std::cout << my_is_pod<int>::value << std::endl; // --> 0

    return 0;
}

B.

if has_feature(__is_pod)

#  define MY_IS_POD(T) __is_pod(T)
#else
#  define MY_IS_POD(T) false
#endif

template <typename T>
struct my_is_pod
{
    static const bool value = MY_IS_POD(T);
};

#include <iostream>

int main (int argc, char* argv[])
{
    std::cout << my_is_pod<int>::value << std::endl; // --> 1

    return 0;
}

I can work around the issue by adding the following code to the Boost's type traits intrinsics detection code:

#if __has_include(<bits/cpp_type_traits.h>)
#  include <bits/cpp_type_traits.h>
#endif

This ensures that libstdc++'s struct __is_pod is introduced before the type traits intrinsics detection.

Thoughts?

Quuxplusone commented 12 years ago
Fixed Boost.TypeTraits (unconditionally disallow the use of clang's __is_pod
and __is_empty intrinsics when used with libstdc++ 4.2):
  https://svn.boost.org/trac/boost/changeset/78344

Thanks Luc for reporting. Also, thanks Eli for Cc'ing me.