Open llvmbot opened 8 years ago
mentioned in issue llvm/llvm-project#26230
Bug llvm/llvm-project#26230 has been marked as a duplicate of this bug.
This still happens with post 17 trunk(a2d68b4bece54bcfa7bfde1e80058ab19b6d1775) https://godbolt.org/z/cbehKnEqa
code
// clang++ -std=c++14 test.cpp
typedef unsigned long size_t;
template<class _Tp, _Tp... _Ip>
struct integer_sequence
{
};
namespace __detail {
template<typename _Tp, size_t ..._Extra> struct __repeat;
template<typename _Tp, _Tp ..._Np, size_t ..._Extra> struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...> {
typedef integer_sequence<_Tp,
_Np...,
sizeof...(_Np) + _Np...,
2 * sizeof...(_Np) + _Np...,
3 * sizeof...(_Np) + _Np...,
4 * sizeof...(_Np) + _Np...,
5 * sizeof...(_Np) + _Np...,
6 * sizeof...(_Np) + _Np...,
7 * sizeof...(_Np) + _Np...,
_Extra...> type;
};
template<size_t _Np> struct __parity;
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
template<> struct __make<0> { typedef integer_sequence<size_t> type; };
template<> struct __make<1> { typedef integer_sequence<size_t, 0> type; };
template<> struct __make<2> { typedef integer_sequence<size_t, 0, 1> type; };
template<> struct __make<3> { typedef integer_sequence<size_t, 0, 1, 2> type; };
template<> struct __make<4> { typedef integer_sequence<size_t, 0, 1, 2, 3> type; };
template<> struct __make<5> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4> type; };
template<> struct __make<6> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4, 5> type; };
template<> struct __make<7> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6> type; };
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<typename _Tp, typename _Up> struct __convert {
template<typename> struct __result;
template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...> > { typedef integer_sequence<_Up, _Np...> type; };
};
template<typename _Tp> struct __convert<_Tp, _Tp> { template<typename _Up> struct __result { typedef _Up type; }; };
}
template<typename _Tp, _Tp _Np> using __make_integer_sequence_unchecked =
typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
template <class _Tp, _Tp _Ep>
struct make_integer_sequence
{
// Clang hangs if you put the typedef before the assert.
typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
static_assert(0 <= _Ep, "std::make_integer_sequence must have a non-negative sequence length");
// GCC fails if you put it after...
// and my IDE hangs whenever I touch it.
};
int main() {
typedef make_integer_sequence<int, -3>::type MakeSeqT;
}
output
<source>:55:90: error: non-type template argument evaluates to -3, which cannot be narrowed to type 'size_t' (aka 'unsigned long') [-Wc++11-narrowing]
55 | typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
| ^
<source>:61:13: note: in instantiation of template type alias '__make_integer_sequence_unchecked' requested here
61 | typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
| ^
<source>:69:13: note: in instantiation of template class 'make_integer_sequence<int, -3>' requested here
69 | typedef make_integer_sequence<int, -3>::type MakeSeqT;
| ^
Killed - processing time exceeded
Program terminated with signal: SIGKILL
Compiler returned: 143
So if we use a really large number as opposed to -3
we also get the same result sans diagnostic: https://godbolt.org/z/xcezdMd96
Likely what is going on is the instiations is happening even though we obtain a diagnostic and the recursion is too deep. I am not sure why we don't stop because we have done too many steps.
The diagnostic is happening in BuildConvertedConstantExpression(...)
and it looks like it then goes on to evaluate the expression further. From what I can see this is expected behavior that the narrowing diagnostic does not halt the evaluation.
CC @erichkeane
@llvm/issue-subscribers-clang-frontend
Author: None (llvmbot)
So if we use a really large number as opposed to
-3
we also get the same result sans diagnostic: https://godbolt.org/z/xcezdMd96Likely what is going on is the instiations is happening even though we obtain a diagnostic and the recursion is too deep. I am not sure why we don't stop because we have done too many steps.
The diagnostic is just a warning-as-error, so we NEED to continue with it (or at least be able to, since there might be a -Wno flag).
Instantiating the templates are really expensive, so we are probably just stuck in a really long loop. It should finish EVENTUALLY, but we're probably exceeding an imp-limits here.
This is why we have the __make_integer_seq
builtin, which does a much better job in these large sizes.
Extended Description
The attached reproducer causes clang to hang after in instantiates the
__make
template with-3
. Clang will emit a C++11 narrowing error before silently hanging. My guess is that clang trys to instantiate the base class of__parity
with the converted value 4294967293.metaprogramming often uses an integer NTTP to control the number of instantiations. If clang instantiates a template with a narrowed NTTP it could be in for a long ride.
I would be willing to work on a fix if somebody could offer direction on the solution.