Bug 97601 - ICE when using type determined by std::tuple_element_t<...>, on tuple generated from type id stored in std::array
Summary: ICE when using type determined by std::tuple_element_t<...>, on tuple generat...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks:
 
Reported: 2020-10-27 18:54 UTC by Milasudril
Modified: 2021-08-12 20:25 UTC (History)
2 users (show)

See Also:
Host: any
Target: any
Build:
Known to work:
Known to fail: 10.1.0, 10.2.0
Last reconfirmed: 2021-08-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Milasudril 2020-10-27 18:54:49 UTC
Code that triggers the bug(s). It uses enum values stored in an std::array, to generate an std::tuple. Using std::tuple_element_t on the generated tuple causes ICE.

Compiler options: -Wall -std=c++20 -O3

#include <memory>
#include <type_traits>
#include <array>
#include <complex>

namespace Enum
{
	template<class T>
	using Empty = std::type_identity<T>;

    template<class T>
	constexpr auto add(T base, std::underlying_type_t<T> offset = 1)
	{
		return static_cast<T>(std::underlying_type_t<T>(base) + offset);
	}

	namespace detail
	{
		template<auto types,
		         template<auto>
		         class EnumItemTraits,
		         class T = std::make_integer_sequence<size_t, types.size()>>
		struct make_tuple_from_array;

		template<auto types, template<auto> class EnumItemTraits, size_t index>
		struct int_to_type_array: public EnumItemTraits<types[index]>
		{
		};

		template<auto types, template<auto> class EnumItemTraits, size_t... indices>
		struct make_tuple_from_array<types,
		                             EnumItemTraits,
		                             std::integer_sequence<size_t, indices...>>
		{
			using type =
			    std::tuple<typename int_to_type_array<types, EnumItemTraits, indices>::type...>;
		};
	}

	template<auto types, template<auto> class EnumItemTraits>
	using TupleFromTypeArray = typename detail::make_tuple_from_array<types, EnumItemTraits>::type;
}

enum class PortType : size_t
{
    RgbaPixels,
    GrayscaleRealPixels,
    GrayscaleComplexPixels,
};

constexpr PortType begin(Enum::Empty<PortType>) { return PortType::RgbaPixels; }
constexpr PortType end(Enum::Empty<PortType>)
{
    return Enum::add(PortType::GrayscaleComplexPixels);
}

using vec4_t __attribute__((vector_size(16))) = float;
using RgbaValue    = vec4_t;
using RealValue    = double;
using ComplexValue = std::complex<RealValue>;

template<PortType id>
struct PortTypeToType;

template<>
struct PortTypeToType<PortType::RgbaPixels>
{
    using type = std::unique_ptr<RgbaValue[]>;
};

template<>
struct PortTypeToType<PortType::GrayscaleRealPixels>
{
    using type = std::unique_ptr<RealValue[]>;
};

template<>
struct PortTypeToType<PortType::GrayscaleComplexPixels>
{
    using type = std::unique_ptr<ComplexValue[]>;
};

template<class T>
struct InputPortType
{
    using type = std::conditional_t<(sizeof(T) <= 16), T, std::reference_wrapper<T const>>;
};

template<class T>
struct InputPortType<std::unique_ptr<T[]>>
{
    using type = T const*;
};

template<class T>
struct InputPortType<std::unique_ptr<T>>
{
    using type = std::reference_wrapper<T const>;
};

namespace detail
{
    template<PortType t>
    struct GenInputPortType
    {
        using type = typename InputPortType<typename PortTypeToType<t>::type>::type;
    };
}

namespace detail
{
    template<class Object, class F, size_t... I>
    constexpr decltype(auto) create_impl(F&& f, std::index_sequence<I...>)
    {
        return Object{f(std::integral_constant<size_t, I>{})...};
    }
}

template<class Tuple, class F, size_t... I>
constexpr decltype(auto) createTuple(F&& f)
{
    return detail::create_impl<Tuple>(std::forward<F>(f),
                                        std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}

template<class T>
void doStuffWithTArg(T);

template<class T>
void doStuffWithT();


template<auto types>
class InArgTuple
{
    using storage_type = Enum::TupleFromTypeArray<types, detail::GenInputPortType>;

public:
    constexpr explicit InArgTuple()
        : m_data{createTuple<storage_type>([]<class Tag>(Tag) {
            using T = typename detail::GenInputPortType<types[Tag::value]>::type;

            // Trunk gets stuck here 
            // internal compiler error: in cxx_eval_constant_expression, at cp/constexpr.c:6188
            using OtherT = std::tuple_element_t<Tag::value, storage_type>;

            static_assert(std::is_same_v<T, OtherT>);
            T foo{};
            // This triggers ICE: in finish_expr_stmt, at cp/semantics.c:681
            // doStuffWithT<OtherT>();
            
            doStuffWithT<T>();  // Not ICE
            
            OtherT bar{};
            // This also triggers ICE: in tsubst_copy, at cp/pt.c:16485
            //doStuffWithTArg(bar);

            doStuffWithTArg(foo);  // Not ICE
            //
            // Also in tsubst_copy, at cp/pt.c:16485
            //
            // return bar;
            //
            return foo;
        })}
    {
    }

    static constexpr auto size() { return types.size(); }

    template<size_t index>
    constexpr auto get() const
    {
        static_assert(index < types.size());
        return std::get<index>(m_data);
    }

private:
    storage_type m_data;
};

void test()
{
    constexpr std::array<PortType, 1> types{PortType::RgbaPixels};
    InArgTuple<types> test{};
}
Comment 1 Marek Polacek 2020-11-19 20:21:35 UTC
Reduced:

typedef int a;
template <typename> struct al;
template <typename b, b am> using an = al<b, __integer_pack(am)...>;
struct {
  void ap();
} ar;
template <auto ar, template <auto> class, class = an<a, ar.ap>> struct as;
template <auto ar, template <auto> class at> using au = as<ar, at>;
enum av {};
template <av> struct aw;
template <auto ar> class ax { using ay = au<ar, aw>; };
ax<ar> az;

The ICE is in the same spot as in bug 87765.
Comment 2 Andrew Pinski 2021-08-12 20:25:55 UTC
https://gcc.godbolt.org/z/n13PKr