#11897 closed Bugs (fixed)
Compile failure in type_traits_detail::mp_valid_impl with CUDA 7.0
Reported by: | Owned by: | John Maddock | |
---|---|---|---|
Milestone: | Boost 1.63.0 | Component: | type_traits |
Version: | Boost 1.60.0 | Severity: | Showstopper |
Keywords: | Cc: |
Description
Including boost/thread/pthread/timespec.hpp and compiling with nvcc 7.0 in C++11 mode throws several errors related to mp_valid_impl. This bug seems to be a compiler bug which is fixed in CUDA 7.5 but as many HPC system only have (and will have) 7.0 this is a real showstopper. Log output is:
/opt/pkg/devel/cuda/7.0/bin/nvcc -std=c++11 BoostMpValid.cu /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/detail/mp_defer.hpp(33): error: no instance of overloaded function "boost::type_traits_detail::mp_valid_impl<F, T...>::check [with F=boost::type_traits_detail::common_type_fold, T=<int_least64_t, int_least64_t, intmax_t>]" matches the argument list argument types are: (int) detected during: instantiation of class "boost::type_traits_detail::mp_valid_impl<F, T...> [with F=boost::type_traits_detail::common_type_fold, T=<int_least64_t, int_least64_t, intmax_t>]" (37): here instantiation of type "boost::type_traits_detail::mp_valid<boost::type_traits_detail::common_type_fold, int_least64_t, int_least64_t, intmax_t>" (50): here instantiation of type "boost::type_traits_detail::mp_defer<boost::type_traits_detail::common_type_fold, int_least64_t, int_least64_t, intmax_t>" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(47): here instantiation of class "boost::common_type<T1, T2, T...> [with T1=int_least64_t, T2=int_least64_t, T=<intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(256): here instantiation of "ToDuration boost::chrono::detail::duration_cast_aux<FromDuration, ToDuration, Period, true, false>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds, Period=boost::ratio<1L, 1000000000L>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(315): here instantiation of "ToDuration boost::chrono::detail::duration_cast<FromDuration, ToDuration>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(789): here instantiation of "boost::enable_if<boost::chrono::detail::is_duration<ToDuration>, ToDuration>::type boost::chrono::duration_cast<ToDuration,Rep,Period>(const boost::chrono::duration<Rep, Period> &) [with ToDuration=boost::chrono::seconds, Rep=int_least64_t, Period=boost::nano]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/thread/pthread/timespec.hpp(51): here /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/detail/mp_defer.hpp(50): error: name followed by "::" must be a class or namespace name detected during: instantiation of type "boost::type_traits_detail::mp_defer<boost::type_traits_detail::common_type_fold, int_least64_t, int_least64_t, intmax_t>" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(47): here instantiation of class "boost::common_type<T1, T2, T...> [with T1=int_least64_t, T2=int_least64_t, T=<intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(256): here instantiation of "ToDuration boost::chrono::detail::duration_cast_aux<FromDuration, ToDuration, Period, true, false>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds, Period=boost::ratio<1L, 1000000000L>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(315): here instantiation of "ToDuration boost::chrono::detail::duration_cast<FromDuration, ToDuration>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(789): here instantiation of "boost::enable_if<boost::chrono::detail::is_duration<ToDuration>, ToDuration>::type boost::chrono::duration_cast<ToDuration,Rep,Period>(const boost::chrono::duration<Rep, Period> &) [with ToDuration=boost::chrono::seconds, Rep=int_least64_t, Period=boost::nano]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/thread/pthread/timespec.hpp(51): here /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/detail/mp_defer.hpp(33): error: no instance of overloaded function "boost::type_traits_detail::mp_valid_impl<F, T...>::check [with F=boost::type_traits_detail::builtin_common_type, T=<int_least64_t, int_least64_t>]" matches the argument list argument types are: (int) detected during: instantiation of class "boost::type_traits_detail::mp_valid_impl<F, T...> [with F=boost::type_traits_detail::builtin_common_type, T=<int_least64_t, int_least64_t>]" (37): here instantiation of type "boost::type_traits_detail::mp_valid<boost::type_traits_detail::builtin_common_type, int_least64_t, int_least64_t>" (50): here instantiation of type "boost::type_traits_detail::mp_defer<boost::type_traits_detail::builtin_common_type, int_least64_t, int_least64_t>" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(96): here instantiation of class "boost::type_traits_detail::common_type_impl<T1, T2> [with T1=int_least64_t, T2=int_least64_t]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(132): here instantiation of class "boost::type_traits_detail::common_type_decay_helper<T1, T2, T1, T2> [with T1=int_least64_t, T2=int_least64_t]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(138): here [ 3 instantiation contexts not shown ] instantiation of class "boost::type_traits_detail::mp_defer_impl<F, T...> [with F=boost::type_traits_detail::common_type_fold, T=<int_least64_t, int_least64_t, intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(47): here instantiation of class "boost::common_type<T1, T2, T...> [with T1=int_least64_t, T2=int_least64_t, T=<intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(256): here instantiation of "ToDuration boost::chrono::detail::duration_cast_aux<FromDuration, ToDuration, Period, true, false>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds, Period=boost::ratio<1L, 1000000000L>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(315): here instantiation of "ToDuration boost::chrono::detail::duration_cast<FromDuration, ToDuration>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(789): here instantiation of "boost::enable_if<boost::chrono::detail::is_duration<ToDuration>, ToDuration>::type boost::chrono::duration_cast<ToDuration,Rep,Period>(const boost::chrono::duration<Rep, Period> &) [with ToDuration=boost::chrono::seconds, Rep=int_least64_t, Period=boost::nano]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/thread/pthread/timespec.hpp(51): here /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/detail/mp_defer.hpp(50): error: name followed by "::" must be a class or namespace name detected during: instantiation of type "boost::type_traits_detail::mp_defer<boost::type_traits_detail::builtin_common_type, int_least64_t, int_least64_t>" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(96): here instantiation of class "boost::type_traits_detail::common_type_impl<T1, T2> [with T1=int_least64_t, T2=int_least64_t]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(132): here instantiation of class "boost::type_traits_detail::common_type_decay_helper<T1, T2, T1, T2> [with T1=int_least64_t, T2=int_least64_t]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(138): here instantiation of class "boost::common_type<T1, T2> [with T1=int_least64_t, T2=int_least64_t]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(37): here instantiation of type "boost::common_type_t<int_least64_t, int_least64_t>" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(42): here instantiation of type "boost::type_traits_detail::common_type_fold<int_least64_t, int_least64_t, intmax_t>" (47): here instantiation of class "boost::type_traits_detail::mp_defer_impl<F, T...> [with F=boost::type_traits_detail::common_type_fold, T=<int_least64_t, int_least64_t, intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/type_traits/common_type.hpp(47): here instantiation of class "boost::common_type<T1, T2, T...> [with T1=int_least64_t, T2=int_least64_t, T=<intmax_t>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(256): here instantiation of "ToDuration boost::chrono::detail::duration_cast_aux<FromDuration, ToDuration, Period, true, false>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds, Period=boost::ratio<1L, 1000000000L>]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(315): here instantiation of "ToDuration boost::chrono::detail::duration_cast<FromDuration, ToDuration>::operator()(const FromDuration &) const [with FromDuration=boost::chrono::duration<int_least64_t, boost::nano>, ToDuration=boost::chrono::seconds]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/chrono/duration.hpp(789): here instantiation of "boost::enable_if<boost::chrono::detail::is_duration<ToDuration>, ToDuration>::type boost::chrono::duration_cast<ToDuration,Rep,Period>(const boost::chrono::duration<Rep, Period> &) [with ToDuration=boost::chrono::seconds, Rep=int_least64_t, Period=boost::nano]" /opt/pkg/devel/boost/1.60.0/gnu/4.8.2/64/opt/include/boost/thread/pthread/timespec.hpp(51): here
I have reduced it to the following MWE which gives the same error (CUDA 7.0, Boost 1.60):
#include <boost/type_traits/common_type.hpp> #include <cstdint> int main(){ boost::common_type<int_least64_t, int_least64_t, intmax_t>::type i; }
Change History (22)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
Possible workaround: Add the following to the end of config/compiler/nvcc.hpp;
// A bug in version 7.0 of CUDA prevents use of variadic templates in some occasions // https://svn.boost.org/trac/boost/ticket/11897 // This is fixed in 7.5. As the following version macro was introduced in 7.5 an existance // check is enough to detect versions < 7.5 #ifndef __CUDACC_VER__ # define BOOST_NO_CXX11_VARIADIC_TEMPLATES #endif
comment:3 by , 7 years ago
Many thanks for investigating this so thoroughly. My only worry about setting BOOST_NO_CXX11_VARIADIC_TEMPLATES as a workaround, is that it may disable otherwise working code in other library interfaces. Does the patch below fix things?
index 5c4303b..4a26d92 100644 --- a/include/boost/type_traits/common_type.hpp +++ b/include/boost/type_traits/common_type.hpp @@ -12,12 +12,13 @@ #include <boost/config.hpp> #include <boost/type_traits/decay.hpp> #include <boost/type_traits/declval.hpp> +#include <boost/detail/workaround.hpp> #if defined(BOOST_NO_CXX11_DECLTYPE) #include <boost/type_traits/detail/common_type_impl.hpp> #endif -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !BOOST_WORKAROUND(__CUDACC_VER__, < 70500) #include <boost/type_traits/detail/mp_defer.hpp> #endif @@ -26,7 +27,7 @@ namespace boost // variadic common_type -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !BOOST_WORKAROUND(__CUDACC_VER__, < 70500) template<class... T> struct common_type {
comment:4 by , 7 years ago
I was proposing to disable this as this is 1 case where variadic templates fail in NVCC 7.0 so I would not rely on its correctness and avoid it.
The proposed patch of yours does not work for 2 reasons: 1) You forgot one #if on line 89 2) The symbol is undefined in 7.0 and prior. Due to the check in BOOST_WORKAROUND for the existance and !=0 of the symbol it will always yield false. I don't see a good way to use that macro here. Using the plain defined(...) or ...>=70500 works.
comment:5 by , 7 years ago
BOOST_MSVC > 1800 |
So using the >= would probably be ok
comment:6 by , 7 years ago
Careful with BOOST_WORKAROUND(__CUDACC_VER__, < 70500)
please, __CUDACC_VER__
is first defined in CUDA 7.5 and will evaluate to undefined
in previous versions. I guess BOOST_WORKAROUND
will not evaluate to true
in such a case.
comment:7 by , 7 years ago
Careful with BOOST_WORKAROUND(CUDACC_VER, < 70500) please, CUDACC_VER is first defined in CUDA 7.5 and will evaluate to undefined in previous versions. I guess BOOST_WORKAROUND will not evaluate to true in such a case.
That's what we want - when CUDACC_VER is not defined it evaluates as 0 when used in a conditional (std mandated behaviour). So if CUDACC_VER is either undefined or less than the specified version then !BOOST_WORKAROUND(CUDACC_VER, < 70500) is false and the variadic template branch is not taken.
So 2 questions:
1) Is there any evidence that variadic template support is causing issues elsewhere in Boost?
2) If I update the patch as below, can someone please test it it?
index c887a89..2b85a39 100644 --- a/include/boost/type_traits/common_type.hpp +++ b/include/boost/type_traits/common_type.hpp @@ -18,7 +18,7 @@ #include <boost/type_traits/detail/common_type_impl.hpp> #endif -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !BOOST_WORKAROUND(__CUDACC_VER__, < 70500) #include <boost/type_traits/detail/mp_defer.hpp> #endif @@ -27,7 +27,7 @@ namespace boost // variadic common_type -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !BOOST_WORKAROUND(__CUDACC_VER__, < 70500) template<class... T> struct common_type { @@ -86,7 +86,7 @@ namespace type_traits_detail #if !defined(BOOST_NO_CXX11_DECLTYPE) -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !BOOST_WORKAROUND(__CUDACC_VER__, < 70500) #if !defined(BOOST_MSVC) || BOOST_MSVC > 1800
comment:8 by , 7 years ago
Yes, but the implementation of BOOST_WORKAROUND
is:
# define BOOST_WORKAROUND(symbol, test) \ ((symbol ## _WORKAROUND_GUARD + 0 == 0) && \ (symbol != 0) && (1 % (( (symbol test) ) + 1)))
There is a check if that symbol evaluates to 0
causing the failure I described above. This is why BOOST_WORKAROUND
cannot be used for this!
So:
1) Currently not. But similar uses of variadic templates will probably fail. Currently nothing else uses mp_defer
(1.60) but other code in future versions may use that as well and run into the same bug.
2) No because BOOST_WORKAROUND
always evaluates to false for this. Prior to 7.5 the symbol is undefined causing the (symbol != 0)
check to fail, and in >=7.5 the 2nd part of the check will fail.
comment:9 by , 7 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
OK, I've changed Boost.Config.
Please see https://github.com/boostorg/config/commit/2090da494ebe0bd79997234a9733191eac425564 and verify that this works for you.
comment:10 by , 7 years ago
Tested with CUDA 7.0 and 7.5 and verified that this works
Thanks for including the fix
follow-up: 13 comment:12 by , 7 years ago
Apple LLVM version 7.0.2 (clang-700.1.81) is also affected by this.
Can you be more specific? Do you mean nvcc on top of clang or just regular clang as shipped by Apple?
follow-up: 14 comment:13 by , 7 years ago
Replying to johnmaddock:
Apple LLVM version 7.0.2 (clang-700.1.81) is also affected by this.
Can you be more specific? Do you mean nvcc on top of clang or just regular clang as shipped by Apple?
Just regular clang as shipped by Apple.
comment:14 by , 7 years ago
Just regular clang as shipped by Apple.
With OP's test case, I was not able to reproduce the error on Apple Clang. Do you have a test case?
Thanks.
$ clang++ --version Apple LLVM version 7.0.2 (clang-700.1.81) Target: x86_64-apple-darwin15.2.0 Thread model: posix $ clang++ -std=c++11 -I boost_1_60_0/ -xc++ - #include <boost/type_traits/common_type.hpp> #include <cstdint> int main(){ boost::common_type<int_least64_t, int_least64_t, intmax_t>::type i; } $ echo $? 0
comment:15 by , 7 years ago
Regression tests for Clang version 7.0.2 (clang-700.1.81) all seem to be passing as well...
comment:16 by , 7 years ago
Yeah, that test case does work. I'll try to extract the minimum piece of code that triggers this from our project over the weekend. But, we did manage to unblock our builds by disabling variadic templates.
comment:17 by , 7 years ago
On OSX, it can be reproduced if you compile it for objective-c++ .
#import <Foundation/Foundation.h> #include <boost/type_traits/common_type.hpp> int main(int argc, const char * argv[]) { boost::common_type<int_least64_t, int_least64_t, intmax_t>::type i; return 0; }
Compiling the above results in :
$ clang++ -std=c++11 -I boost_1_60_0/ -ObjC++ test.mm In file included from test.mm:2: In file included from boost_1_60_0/boost/type_traits/common_type.hpp:21: boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:28:5: warning: declaration does not declare anything [-Wmissing-declarations] static boost::true_type check(int); ^~~~~~~~~~~~~~~~~~~~~~~ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:31:5: warning: declaration does not declare anything [-Wmissing-declarations] static boost::false_type check(...); ^~~~~~~~~~~~~~~~~~~~~~~~ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:33:27: error: use of undeclared identifier 'check' using type = decltype(check<F>(0)); ^ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:33:33: error: cannot refer to class template 'F' without a template argument list using type = decltype(check<F>(0)); ^ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:24:35: note: template is declared here template<template<class...> class F, class... T> ^ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:37:1: error: no type named 'type' in 'boost::type_traits_detail::mp_valid_impl<common_type_fold, long long, long long, long>' using mp_valid = typename mp_valid_impl<F, T...>::type; ^~~~~ boost_1_60_0/boost/type_traits/detail/mp_defer.hpp:50:95: note: in instantiation of template type alias 'mp_valid' requested here template<template<class...> class F, class... T> using mp_defer = typename boost::conditional<mp_valid<F, T...>::value, mp_defer_impl<F, T...>, mp_empty>::type; ^ boost_1_60_0/boost/type_traits/common_type.hpp:47:55: note: in instantiation of template type alias 'mp_defer' requested here struct common_type<T1, T2, T...>: type_traits_detail::mp_defer<type_traits_detail::common_type_fold, T1, T2, T...> ^ test.mm:5:9: note: in instantiation of template class 'boost::common_type<long long, long long, long>' requested here boost::common_type<int_least64_t, int_least64_t, intmax_t>::type i; ^ 2 warnings and 3 errors generated.
The root cause is the expansion of a macro "check" defined in the OSX_SDK_10.11's AssertMacros.h . Defining either BOOST_NO_CXX11_TEMPLATE_ALIASES or BOOST_NO_CXX11_VARIADIC_TEMPLATES excludes mp_defer.hpp therefore that works as a workaround. What also works is #undef check before this inclusion.
comment:18 by , 7 years ago
Seems to be fixed in develop : https://github.com/boostorg/type_traits/commit/f80cbb0dad16f974815a4ad8208f056ec58c9efc
comment:19 by , 7 years ago
The check macro issue is presumably a whole different issue, but if not then yes, this should be fixed in the next release.
comment:20 by , 6 years ago
Apparently the bug is back with CUDA 8.0 (tested with Boost 1.61.0). With the original repro code:
$ /usr/local/cuda-7.5/bin/nvcc bug.cu -std=c++11 // No issue $ /usr/local/cuda-8.0/bin/nvcc bug.cu -std=c++11 error: class "boost::common_type<int_least64_t, int_least64_t, intmax_t>" has no member "type"
follow-up: 22 comment:21 by , 6 years ago
Milestone: | To Be Determined → Boost 1.63.0 |
---|
You're right - CUDA 8 has the same issue! I've just pushed some changes to Boost.Config develop to fix this.
comment:22 by , 6 years ago
I forwarded the issue to the NVIDIA developers, they fixed the problem for the next CUDA release.
This bug was introduced in 1.60. 1.59 is working fine. As the following code shows, the problem is related to variadic templates:
Output:
So only the non-variadic version works. A simple workaround is probably to deactivate variadic templates by defining BOOST_NO_CXX11_VARIADIC_TEMPLATES for nvcc < 7.5. 7.5 is working so this can be used there.