mpark / variant

C++17 `std::variant` for C++11/14/17
https://mpark.github.io/variant
Boost Software License 1.0
659 stars 88 forks source link

NVCC & C++14 Constexpr #70

Closed ax3l closed 4 years ago

ax3l commented 4 years ago

With Nvidia's nvcc, tested in versions 10.1.243 and 10.2.89, using gcc (v4.9-v8) as host compiler, the following example compiles with -std=c++11 but not with -std=c++14.

// file: main.cu
#include <mpark/variant.hpp>

int main()
{
    return 0;
}

The C++14 error is:

mpark/variant.hpp: In function ‘constexpr decltype(auto) mpark::visit(Visitor&&, Vs&& ...)’:
mpark/variant.hpp:2017:96: error: parameter packs not expanded with ‘...’:
     return (detail::all({!vs.valueless_by_exception()...})
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                     ^                                                                                                      
mpark/variant.hpp:2017:96: note:         ‘vs’

Naive work-around so far:

diff --git a/include/mpark/variant.hpp b/include/mpark/variant.hpp
index ef496619b..3a400e546 100644
--- a/include/mpark/variant.hpp
+++ b/include/mpark/variant.hpp
@@ -1998,7 +1998,7 @@ namespace mpark {
     return false;
   }

-#ifdef MPARK_CPP14_CONSTEXPR
+#if defined(MPARK_CPP14_CONSTEXPR) && !defined(__NVCC__)
   namespace detail {

     inline constexpr bool all(std::initializer_list<bool> bs) {
ax3l commented 4 years ago

Cross-link Nvidia Bug report: 2767419 Update: Confirmed by Nvidia to be fixed for the next CUDA release (latest CUDA release today: 10.2.89).

ax3l commented 4 years ago

The problem is likely in detail::all which uses a constexpr for/if... Passing --expt-relaxed-constexpr to nvcc does not solve the problem either.

It compiles with clang++ and g++ with -std=c++14 features ...

ax3l commented 4 years ago

Another minimal reproducer developed by @maxpkatz :

#include <initializer_list>namespace detail {    
    bool f(std::initializer_list<bool> y) { return true; }
}  // namespace detail
template <typename... X>
bool g(X &&... x) {
    // breaks:
    return detail::f({!x.valueless_by_exception()...});
    // works only for N>1 parameter packs:
    // return detail::f(std::initializer_list<bool>(!x.valueless_by_exception()...));
    // fails as well:
    // return detail::f(std::initializer_list<bool>{!x.valueless_by_exception()...});
}

int main() {
    return 0;
}
mpark commented 4 years ago

Fixed in 3c7fc8266bb46046b42c2dc2663f9f505f0cec28