[Bug c++/113754] New: GCC complains when using a type that depends on lambda
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113754 Bug ID: 113754 Summary: GCC complains when using a type that depends on lambda Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: milasudril at gmail dot com Target Milestone: --- I tried to use template using unique_ptr_deleter = std::unique_ptr; As described by https://andreasfertig.blog/2022/08/cpp-insights-lambdas-in-unevaluated-contexts/ It works well as long as I do not try define it in a header file. If gcc detects a from a header file that uses unique_ptr_deleter, I get the warning lib/array_classes/./memory_block.hpp:12:8: error: 'memory_block' has a field 'unique_ptr_deleter terraformer::memory_block::m_pointer' whose type has internal linkage [-Werror=subobject-linkage] Clang do generate any warnings. Stand-alone snippet to reproduce the issue: #include #include # 7 "lib/array_classes/./memory_block.hpp" template using unique_ptr_deleter = std::unique_ptr; class memory_block { public: private: unique_ptr_deleter m_pointer; }; # 4 "lib/array_classes/memory_block.test.cpp"
[Bug c++/109287] New: Optimizing sal shr pairs when inlining function
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109287 Bug ID: 109287 Summary: Optimizing sal shr pairs when inlining function Product: gcc Version: 12.2.0 URL: https://gcc.godbolt.org/z/aPTsjc1sM Status: UNCONFIRMED Keywords: missed-optimization Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: milasudril at gmail dot com Target Milestone: --- Target: x86-64_linux_gnu I was trying to construct a span type to be used for working with a tile-based image ``` #include #include #include template class span_2d_tiled { public: using IndexType = size_t; static constexpr size_t tile_size() { return TileSize; } constexpr explicit span_2d_tiled(): span_2d_tiled{0u, 0u, nullptr} {} constexpr explicit span_2d_tiled(IndexType w, IndexType h, T* ptr): m_tilecount_x{1 + (w - 1)/TileSize}, m_tilecount_y{1 + (h - 1)/TileSize}, m_ptr{ptr} {} constexpr auto tilecount_x() const { return m_tilecount_x; } constexpr auto tilecount_y() const { return m_tilecount_y; } constexpr T& operator()(IndexType x, IndexType y) const { auto const x_tile = x/TileSize; auto const y_tile = y/TileSize; auto const x_offset = x%TileSize; auto const y_offset = y%TileSize; auto const tile_start = y_tile*m_tilecount_x + x_tile; return *(m_ptr + tile_start + y_offset*TileSize + x_offset); } private: IndexType m_tilecount_x; IndexType m_tilecount_y; T* m_ptr; }; template void visit_tiles(size_t x_count, size_t y_count, Func&& f) { for(size_t k = 0; k != y_count; ++k) { for(size_t l = 0; l != x_count; ++l) { for(size_t y = 0; y != TileSize; ++y) { for(size_t x = 0; x != TileSize; ++x) { f(l*TileSize + x, k*TileSize + y); } } } } } void do_stuff(float); void call_do_stuff(span_2d_tiled foo) { visit_tiles(foo.tilecount_x(), foo.tilecount_y(), [foo](size_t x, size_t y){ do_stuff(foo(x, y)); }); } ``` Here, the user of this API wants to access individual pixels. Thus, the coordinates are transformed before calling f. To do so, we multiply by TileSize and adds the appropriate offset. In the callback, the pixel value is looked up. But now we must find out what tile it is, and the offset within that tile, which means that the inverse transformation must be applied. As can be seen in the Godbolt link, GCC does not fully understand what is going on here. However, latest clang appears to do a much better job with the same settings. It also unrolls the inner loop, much better than if I used ``` #pragma GCC unroll 16 ```
[Bug c++/107862] New: Returning an std::vector from a lambda fails to be constexpr, while a custom class with allocated storage works
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107862 Bug ID: 107862 Summary: Returning an std::vector from a lambda fails to be constexpr, while a custom class with allocated storage works Product: gcc Version: 12.2.0 URL: https://godbolt.org/z/dve3Yx8ax Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: milasudril at gmail dot com Target Milestone: --- Host: x86-64_linux_gnu Target: x86-64_linux_gnu Minimal working example: #include #include #include struct Test { using value_type = int; constexpr Test(){ data = new value_type(0); } constexpr ~Test(){ delete data; } constexpr unsigned size() const { return 1; } constexpr auto begin() const { return data; } constexpr auto end() const { return data + 1; } private: value_type* data; }; consteval auto dynamic_data_to_array(auto generator) { auto test = generator(); using VT = typename decltype(test)::value_type; std::array data; std::copy(test.begin(), test.end(), data.begin()); return data; } constexpr Test get_test() { return Test(); } int main() { // Does not work constexpr auto data0 = dynamic_data_to_array([] { return std::vector{0};}); constexpr auto data1 = dynamic_data_to_array([] { return Test{};}); return data1[0]; } It works to return a Test object here, but not an std::vector. Compiler output: :22:29: in 'constexpr' expansion of 'test.std::vector::size()' :22:33: error: the value of 'test' is not usable in a constant expression 22 | std::array data; | ^~~~ :19:10: note: 'test' was not declared 'constexpr' 19 | auto test = generator(); | ^~~~ :22:29: note: in template argument for type 'long unsigned int' 22 | std::array data; |~^~ :22:29: in 'constexpr' expansion of 'test.std::vector::size()' :22:33: error: the value of 'test' is not usable in a constant expression 22 | std::array data; | ^~~~ :19:10: note: 'test' was not declared 'constexpr' 19 | auto test = generator(); | ^~~~ :22:29: note: in template argument for type 'long unsigned int' 22 | std::array data; I am not sure if this is by the standard, or if this is related to some missing implementation details in the standard library. Note: clang doesn't like it either.
[Bug c++/107123] Size deduction for vector size in template fails
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107123 --- Comment #2 from milasudril at gmail dot com --- > It would be nice to standardized the vector attribute. Good features to have: constexpr std::size (and also std::ssize) template inline constexpr std::is_simd_type_v = ...; namespace std { template struct simd_element_type{ using type = ...; }; template simd_element_type_t = typename simd_element_type::type; } I belive the working paper is p2638r0 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2638r0.pdf
[Bug c++/107123] New: Size deduction for vector size in template fails
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107123 Bug ID: 107123 Summary: Size deduction for vector size in template fails Product: gcc Version: 12.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: milasudril at gmail dot com Target Milestone: --- Host: x86-64_linux_gnu Target: x86-64_linux_gnu I tried to write a generic inner product implementation, accepting vectorized arguments: ```c++ #include #include template concept arithmetic = std::is_arithmetic_v; template using native_vector [[gnu::vector_size(sizeof(T)*N)]] = T; template auto inner_product(native_vector a, native_vector b) { auto const prod = a * b; T ret{}; for(size_t k = 0; k != N; ++k) { ret += prod[k]; } return ret; } auto test(native_vector a, native_vector b) { return inner_product(a, b); } ``` Apparently, it is not possible to deduce N here: ``` : In function 'auto test(native_vector, native_vector)': :23:25: error: no matching function for call to 'inner_product(native_vector&, native_vector&)' 23 | return inner_product(a, b); |~^~ :11:6: note: candidate: 'template auto inner_product(native_vector, native_vector)' 11 | auto inner_product(native_vector a, native_vector b) | ^ :11:6: note: template argument deduction/substitution failed: :23:25: note: couldn't deduce template parameter 'N' 23 | return inner_product(a, b); ``` I would appreciate if size deduction worked like for std::array: ```c++ #include template auto inner_product(std::array a, std::array b) { T ret{}; for(size_t k = 0; k != N; ++k) { ret += a[k]*b[k]; } return ret; } auto test(std::array a, std::array b) { return inner_product(a, b); // N deduced to 4 } ``` The problem is present on gcc 10-trunk.
[Bug c++/97601] New: ICE when using type determined by std::tuple_element_t<...>, on tuple generated from type id stored in std::array
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97601 Bug ID: 97601 Summary: ICE when using type determined by std::tuple_element_t<...>, on tuple generated from type id stored in std::array Product: gcc Version: 10.2.1 URL: https://gcc.godbolt.org/z/n13PKr Status: UNCONFIRMED Keywords: ice-on-valid-code Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: milasudril at gmail dot com Target Milestone: --- Host: any Target: any 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 #include #include #include namespace Enum { template using Empty = std::type_identity; template constexpr auto add(T base, std::underlying_type_t offset = 1) { return static_cast(std::underlying_type_t(base) + offset); } namespace detail { template class EnumItemTraits, class T = std::make_integer_sequence> struct make_tuple_from_array; template class EnumItemTraits, size_t index> struct int_to_type_array: public EnumItemTraits { }; template class EnumItemTraits, size_t... indices> struct make_tuple_from_array> { using type = std::tuple::type...>; }; } template class EnumItemTraits> using TupleFromTypeArray = typename detail::make_tuple_from_array::type; } enum class PortType : size_t { RgbaPixels, GrayscaleRealPixels, GrayscaleComplexPixels, }; constexpr PortType begin(Enum::Empty) { return PortType::RgbaPixels; } constexpr PortType end(Enum::Empty) { return Enum::add(PortType::GrayscaleComplexPixels); } using vec4_t __attribute__((vector_size(16))) = float; using RgbaValue= vec4_t; using RealValue= double; using ComplexValue = std::complex; template struct PortTypeToType; template<> struct PortTypeToType { using type = std::unique_ptr; }; template<> struct PortTypeToType { using type = std::unique_ptr; }; template<> struct PortTypeToType { using type = std::unique_ptr; }; template struct InputPortType { using type = std::conditional_t<(sizeof(T) <= 16), T, std::reference_wrapper>; }; template struct InputPortType> { using type = T const*; }; template struct InputPortType> { using type = std::reference_wrapper; }; namespace detail { template struct GenInputPortType { using type = typename InputPortType::type>::type; }; } namespace detail { template constexpr decltype(auto) create_impl(F&& f, std::index_sequence) { return Object{f(std::integral_constant{})...}; } } template constexpr decltype(auto) createTuple(F&& f) { return detail::create_impl(std::forward(f), std::make_index_sequence>{}); } template void doStuffWithTArg(T); template void doStuffWithT(); template class InArgTuple { using storage_type = Enum::TupleFromTypeArray; public: constexpr explicit InArgTuple() : m_data{createTuple([](Tag) { using T = typename detail::GenInputPortType::type; // Trunk gets stuck here // internal compiler error: in cxx_eval_constant_expression, at cp/constexpr.c:6188 using OtherT = std::tuple_element_t; static_assert(std::is_same_v); T foo{}; // This triggers ICE: in finish_expr_stmt, at cp/semantics.c:681 // doStuffWithT(); doStuffWithT(); // 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 constexpr auto get() const { static_assert(index < types.size()); return std::get(m_data); } private: storage_type m_data; }; void test() { constexpr std::array types{PortType::RgbaPixels}; InArgTuple test{}; }