c++: Fix bogus error with __integer_pack [PR94490]

Here we issue a bogus:

error: '(0 ? fake_tuple_size_v<int> : fake_tuple_size_v<int>)' is not a constant expression

because cxx_constant_value in expand_integer_pack gets

*(0 ? VIEW_CONVERT_EXPR<const int>(fake_tuple_size_v) : VIEW_CONVERT_EXPR<const int>(fake_tuple_size_v))

which is a REFERENCE_REF_P and we evaluate its operand to 3, so we end
up with *3 and that fails.  Sounds like we need to get rid of the
REFERENCE_REF_P then.  That is what tsubst_copy_and_build/INDIRECT_REF
will do:

        if (REFERENCE_REF_P (t))
          {
            /* A type conversion to reference type will be enclosed in
               such an indirect ref, but the substitution of the cast
               will have also added such an indirect ref.  */
            r = convert_from_reference (r);
          }

so I think it's reasonable to call instantiate_non_dependent_expr_sfinae.

	PR c++/94490

gcc/cp/ChangeLog:

	* pt.c (expand_integer_pack): Call
	instantiate_non_dependent_expr_sfinae.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/integer-pack5.C: New test.
This commit is contained in:
Marek Polacek 2021-11-06 18:10:39 -04:00
parent cde87638bf
commit 9af081003f
2 changed files with 30 additions and 0 deletions

View File

@ -3792,6 +3792,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
}
else
{
hi = instantiate_non_dependent_expr_sfinae (hi, complain);
hi = cxx_constant_value (hi);
int len = valid_constant_size_p (hi) ? tree_to_shwi (hi) : -1;

View File

@ -0,0 +1,29 @@
// PR c++/94490
// { dg-do compile { target c++14 } }
template<class T>
constexpr int fake_tuple_size_v = 3;
template<int...> struct intseq {};
// So that it compiles with clang++.
#if __has_builtin(__make_integer_seq)
using size_t = decltype(sizeof(1));
template<typename, size_t... _Indices>
using _IdxTuple = intseq<_Indices...>;
template<int N> using genseq = __make_integer_seq<_IdxTuple, size_t, N>;
#else
template<int N> using genseq = intseq<__integer_pack(N)...>;
#endif
template<int A, class S = genseq<0 ? A : A>>
struct arith_result
{ };
template<typename T>
auto Mul(const T&)
{
return [](auto) { return arith_result<fake_tuple_size_v<T>> { }; }(0);
}
auto x = Mul(0);