nvcc bug report? Compiling host code with nvcc and Visual Studio 2015 with a use of std::allocator_traits results in ICE

I’ve been trying to use CUDA from existing code base and encountered an internal compiler error. I’ve tried to reproduce context for the error which resulted in the following code.

#include <memory>

struct base {};

template <class base_t, class alloc_t, class...Args>
struct S :base_t
{
	typedef typename std::allocator_traits<alloc_t>::template rebind_alloc<int> allocator_type;
	//typedef typename trait<alloc_t>::template rebind<int> allocator_type; //okay
	//typedef typename trait2<alloc_t>::template rebind<int> allocator_type; //okay. Here the same way of rebinding is used as in inpmlementation of MSVC's std::allocator_traits.
	//typedef typename _Get_rebind_type<alloc_t, int>::type allocator_type; //okay
};

//template <class T> struct rebindable_type {};
template <class T>
using rebindable_type = std::allocator<T>;

int main(int, char**)
{
	S<base, rebindable_type<char>, void> s;
	return 0;
}

However, this error happens with std::allocator_traits for some reason. I even tried to copy-paste implementation of allocator_traits tо own implementation as specified below, but the resulting code cause no error. The corresponding code is commented out above, and the used classes are specified as follows. Helper elements used by trait2 are copy-pasted from MSVC xmemory0 header.

template <class T, class t, class Def>
typename T::template rebind<t>::other choose_def(int);
template <class T, class t, class Def>
Def choose_def(...);

template <class T> class trait {};
template <template <class> class C, class T> struct trait<C<T>> 
{
	template <class U>
	using rebind = decltype(choose_def<C<T>, U, C<U>>(int()));
};

#define _GET_TYPE_OR_DEFAULT(TYPE, DEFAULT) \
	{ \
	template<class _Uty> \
		static auto _Fn(int) \
			-> _Identity<typename _Uty::TYPE>; \
 \
	template<class _Uty> \
		static auto _Fn(_Wrap_int) \
			-> _Identity<DEFAULT>; \
 \
	typedef decltype(_Fn<_Ty>(0)) _Decltype; \
	typedef typename _Decltype::type type; \
	}

template<class _Newfirst,
	class _Ty>
	struct _Replace_first_parameter;

template<class _Newfirst,
	template<class, class...> class _Ty,
	class _First,
	class... _Rest>
	struct _Replace_first_parameter<_Newfirst, _Ty<_First, _Rest...> >
	{	// given _Ty<_First, _Rest...>, replace _First
	typedef _Ty<_Newfirst, _Rest...> type;
	};

template<class _Ty>
	struct _Identity
	{	// map _Ty to type unchanged, without operator()
	typedef _Ty type;
	};

struct _Wrap_int
	{	// wraps int so that int argument is favored over _Wrap_int
	_Wrap_int(int)
		{	// do nothing
		}
	};

#define _COMMA ,

template<class _Ty,
	class _Other>
	struct _Get_rebind_type
	_GET_TYPE_OR_DEFAULT(template rebind<_Other>::other,
		typename _Replace_first_parameter<_Other _COMMA _Uty>::type);

template <class T> struct trait2
{
	template <class U>
	using rebind = typename _Get_rebind_type<T, U>::type;
};

I used CUDA 9.1 to compile this.

I apologize if this is the wrong place to post this, but it seems like it is an NVCC bug, but I am not sure.

  1. ICE is bug by definition
  2. there is code tag on this forum (last button in the bar above edit box) which you can use to make your code more readable

I don’t have idea what’s wrong in this code, but it looks it using a very compiler-specific machinery. NVCC has gcc (or llvm?) based frontend, so i doubt that it should be able to compile msvc-specific tricks used in second example

BulatZiganshin, thank you for the reply. I somehow completely missed that code button. I edited the post to insert the code tags.

There is no very compiler-specific machinery. MSVC implements std::allocator_traits::rebind_alloc as

template<class _Other>
using rebind_alloc = typename _Get_rebind_type<_Alloc, _Other>::type;

(together with other template methods and type aliases). Implementation of _Get_rebind_type is copy-pasted to the first post from the MSVC’s header. And the inclusion of the “memory” header is only made for std::allocator_traits. Should one comment out the line where S::allocator_type is defined with a use of std::allocator_traits and use any of the other definitions of allocator_type, there would be no need to include the file (although, the ICE would be gone as well).