[Bug c++/113754] New: GCC complains when using a type that depends on lambda

2024-02-04 Thread milasudril at gmail dot com via Gcc-bugs
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

2023-03-26 Thread milasudril at gmail dot com via Gcc-bugs
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

2022-11-24 Thread milasudril at gmail dot com via Gcc-bugs
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

2022-10-03 Thread milasudril at gmail dot com via Gcc-bugs
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

2022-10-02 Thread milasudril at gmail dot com via Gcc-bugs
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

2020-10-27 Thread milasudril at gmail dot com via Gcc-bugs
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{};
}