Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

Invalid cxx_rvalue_references feature detection with clang.

George_E_
Beginner
778 Views

It is impossible to use construct method from allocators with variadic template.

In TBB v4.3 Update 2 rvalue reference support is detected next way:

    #define __TBB_CPP11_RVALUE_REF_PRESENT             (__has_feature(__cxx_rvalue_references__) && (__TBB_GCC_VERSION >= 40300 || _LIBCPP_VERSION))

I'm using clang 3.6 from sources and not using libcpp, thus it is false. Also _TBB_GCC_VERSION is 4.2.1, so it is less than 40300. So rvalue reference is actually supported by my compiler, but detected as not supported in tbb_config.h.

0 Kudos
6 Replies
Anton_P_Intel
Employee
778 Views

Usually construct method of an allocator is a thin wrapper over contained type constructor call, i.e. forwarding function:

    template<typename U, typename... Args>
    void construct(U *p, Args&&... args)
        { ::new((void *)p) U(std::forward<Args>(args)...); }

So it relies on presence std::forward function, which internally implemented via r-value references. Usually if C++ compiler supports r-value reference then C++  standard library which comes with it provide std::forward as well.

But, as Clang may use two standard libraries: libc++ and GNU libstdc++, presence of std::forward needed to be checked based on knowing which library is used in fact.

In practice, version of GNU libstdc++ can be bound to version of GCC. Clang defines appropriate GCC version macroses according to version of GCC environment it uses, that is why there are two parts in  definition of  __TBB_CPP11_RVALUE_REF_PRESENT: ( __TBB_GCC_VERSION >= 40300 || _LIBCPP_VERSION)

So there are several variants to use varaidic version of tbb allocator construct method:

1. Use appropriate C++ standard library  (libc++ of any version or libstdc++4.3 or greater, there are some information on compiling Clang with libstdc++ here: http://clang.llvm.org/cxx_status.html )

2. provide your own implementation of std::forward and patch TBB accordingly.

 

0 Kudos
George_E_
Beginner
778 Views

Hi, I think you misunderstood me. I'm telling that my compiler (clang3.6 built from sources with libstdc++-4.9) do have std::function implemented, but __TBB_GCC_VERSION is 40201 (__GNUC__, __GNUC_MINOR__ abd __GNUC_PATCHLEVEL__ are hardcoded in clang to 4.2.1). Simply changing that check to __TBB_GCC_VERSION >= 40201 fixes my issue, but this would not work for older libstdc++ versions.

Thus check in TBB for __TBB_CPP11_RVALUE_REF_PRESENT is not correct: __TBB_GCC_VERSION is not related to libstdc++ version at all.

Proper way would be checking __GLIBCXX__, but it doesn't have some simple value we can check against. See also http://stackoverflow.com/questions/21622561/how-to-detect-the-libstdc-version-in-clang

0 Kudos
Anton_P_Intel
Employee
778 Views

Ok. Now it seen clearly where the problem is. Let see that we can do about it.

0 Kudos
George_E_
Beginner
778 Views

Is there any way to track this issue, or should I add this to TBB bug tracker if it is available anywhere? If not, how do I know if this issue is planned/not planned to be fixed.

0 Kudos
Vladimir_P_1234567890
778 Views

hello George,

Do you have thoughts who it can be detected? if yes, could you submit a patch via our contribution page https://www.threadingbuildingblocks.org/submit-contribution?

--Vladimir

0 Kudos
Konrad_Z_
Beginner
778 Views

Hey everyone,

The issue described by George is just one symptom of a more general one. Here's a more (but maybe not fully) comprehensive list of macros from tbb_config.h that are undefined/false when using Clang 3.6 with libstdc++ 3.4.20 (shipped with GCC 4.9):

  • __TBB_CPP11_RVALUE_REF_PRESENT
  • __TBB_CPP11_STD_BEGIN_END_PRESENT
  • __TBB_EXCEPTION_PTR_PRESENT
  • __TBB_CPP11_TYPE_PROPERTIES_PRESENT
  • __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT
  • __TBB_MOVE_IF_NOEXCEPT_PRESENT
  • __TBB_ALLOCATOR_TRAITS_PRESENT
  • __TBB_MAKE_EXCEPTION_PTR_PRESENT
  • __TBB_GCC_BUILTIN_ATOMICS_PRESENT

As George mentioned, the proper way would be to check __GLIBCXX__. Its value is a simple int correlated with a GCC version as described on GCC website: https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html . I'm hesitant to submit a patch as I'm afraid there might be cases where relying __TBB_GCC_VERSION value is important for proper detection on other platforms (e.g. with ICC).

Side note: even when __TBB_CPP11_RVALUE_REF_PRESENT is manually set to 1, popping copy-disabled, move-enabled objects from tbb::concurrent_priority_queue still results in a compilation error as __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT is undefined.

0 Kudos
Reply