[Bug c++/119659] New: [OpenMP] append_args in iobj member function applies to the wrong paramater

2025-04-06 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119659

Bug ID: 119659
   Summary: [OpenMP] append_args in iobj member function applies
to the wrong paramater
   Product: gcc
   Version: 15.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: waffl3x at gcc dot gnu.org
  Target Milestone: ---

Created attachment 61026
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61026&action=edit
Output with -ftree-dump-gimple

Another case that got found in the final stages of my current
patch, already fixed, this is just for records.

The issue is more obvious in the attached tree dump, despite
append_args being specified for parameter 'a', it is instead
adjusting the second parameter 'b' instead.

https://godbolt.org/z/4o4cc46eY
```
struct S {
  template
  void v(int *, int *) {}

  #pragma omp declare variant(v) match(construct={dispatch}) \
 adjust_args(need_device_ptr: a)
  template
  void b(int *a, int *b) {}
};

void f(int *p0, int *p1)
{
  S s{};
  #pragma omp dispatch
  s.b(p0, p1);
}
```

[Bug c++/119674] New: defaulted assignment operator with xobj syntax is an xobj function instead of an iobj function

2025-04-07 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119674

Bug ID: 119674
   Summary: defaulted assignment operator with xobj syntax is an
xobj function instead of an iobj function
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: minor
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: waffl3x at gcc dot gnu.org
  Target Milestone: ---

dcl.fct.def.default p2
An explicitly defaulted special member function F1 is allowed to differ
from the corresponding special member function F2 that would have been
implicitly declared, as follows: 
(2.2) if F2 has an implicit object parameter of type “reference to C”,
  F1 may be an explicit object member function whose explicit
  object parameter is of (possibly different) type “reference to
  C”, in which case the type of F1 would differ from the type of F2
  in that the type of F1 has an additional parameter;

I am interpreting this to mean that the declaration of the function
that is defaulted does not effect the actual function that is
generated.  I assume there is another passage somewhere that specifies
this more directly.

I'm not 100% sure if my interpretation is correct, but if it is our
current implementation is not.

```
struct S0 {
  S0& operator=(S0 const&) = default;
};
struct S1 {
  S1& operator=(this S1&, S1 const&) = default;
};

int main()
{
  // well-formed, accepted
  S0& (S0::* p0)(S0 const&) = &S0::operator=;
  // well-formed, rejected
  S1& (S1::* p1)(S1 const&) = &S1::operator=;
  // ill-formed, rejected
  S0& (* p2)(S0&, S0 const&) = &S0::operator=;
  // ill-formed, accepted
  S1& (* p3)(S1&, S1 const&) = &S1::operator=;
}
```

[Bug c++/119659] [OpenMP] append_args in iobj member function applies to the wrong paramater

2025-04-08 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119659

--- Comment #1 from Alex  ---
I accidentally left the template head in the original test case, it
doesn't change the results at all but does slightly over complicate the
test case.

```
struct S {
  void v(int *, int *) {}

  #pragma omp declare variant(v) match(construct={dispatch}) \
 adjust_args(need_device_ptr: a)
  void b(int *a, int *b) {}
};


void f(int *p0, int *p1)
{
  S s{};
  #pragma omp dispatch
  s.b(p0, p1);
}
```

[Bug c++/119736] New: rejected/ICEs when non type template parameter used as an argument to a const ref non type template parameter

2025-04-11 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119736

Bug ID: 119736
   Summary: rejected/ICEs when non type template parameter used as
an argument to a const ref non type template parameter
   Product: gcc
   Version: 15.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: waffl3x at gcc dot gnu.org
  Target Milestone: ---

https://godbolt.org/z/aE7xEnzzq
```
template struct takes_static_ref {};

template
struct make_static_ref {
  static constexpr auto const& ref = Data;
};

using ice = takes_static_ref::ref>;
```
https://godbolt.org/z/EEjMj9ab4
```
template
void takes_static_ref_f() {}

template
struct make_static_ref {
  static constexpr auto const& ref = Data;
};

template void takes_static_ref_f::ref>();
```

This only triggers in C++17 and up, I am fairly certain this is valid
code but it doesn't seem like it was ever accepted in GCC, it's just
the ICE that is new.

All the cases beyond here are not regressions, but I do believe they
are all valid code.

https://godbolt.org/z/qG66n6Mse
```
template struct takes_static_ref {};

template
struct make_static_ref {
  using direct = takes_static_ref;

  static constexpr auto const& ref = Data;
  using from_member = takes_static_ref;
};

using direct = make_static_ref<42>::direct;
using from_member = make_static_ref<42>::from_member;
```

And finally these are what should be a fairly exhaustive list of cases,
the ones you would expect to work still work and are just included to
illustrate that the problematic cases are probably valid C++ code.

https://godbolt.org/z/7KabYPqTr
```
template struct takes_static_ref {};
template struct takes_value {};

template
void takes_static_ref_f() {}

template
struct make_static_ref {
static constexpr int const& ref = Data;
};

template
inline constexpr const auto& make_static_ref_inline = Data;

inline int my_global_var = 42;
using with_global = takes_static_ref;
template void takes_static_ref_f();

struct S {
  inline static int my_static_member = 42;
  using with_static_member = takes_static_ref;
};
using with_static_member = takes_static_ref;
template void takes_static_ref_f();

void f()
{
static int my_static_var = 42;
takes_static_ref with_local_static;
takes_static_ref_f();

static constexpr auto data_0 = make_static_ref<42>::ref;
static constexpr auto data_1 = make_static_ref_inline<42>;
static constexpr auto const& data_ref_0 = make_static_ref<42>::ref;
static constexpr auto const& data_ref_1 = make_static_ref_inline<42>;
takes_value v_0;
takes_value v_1;
takes_static_ref r_0;
takes_static_ref r_1;
takes_static_ref_f();
takes_static_ref_f();
}

using sr_0 = takes_value::ref>;
using sr_1 = takes_value>;

using sr_0 = takes_static_ref::ref>;
using sr_1 = takes_static_ref>;

template void takes_static_ref_f::ref>();
template void takes_static_ref_f>();
```

[Bug c++/119775] New: [OpenMP] ICE with append_args in iobj member function

2025-04-13 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119775

Bug ID: 119775
   Summary: [OpenMP] ICE with append_args in iobj member function
   Product: gcc
   Version: 15.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: waffl3x at gcc dot gnu.org
  Target Milestone: ---

https://godbolt.org/z/PYff7Gxoa
```
enum omp_interop_t : __UINTPTR_TYPE__;

struct S {
  void v(int, omp_interop_t) {}

  #pragma omp declare variant(v) match(construct={dispatch}) \
 append_args(interop(target))
  void b(int) {}
};

void f()
{
  #pragma omp dispatch
  S{}.b(42);
}
```
:14:3: internal compiler error: tree check: accessed operand 6 of
call_expr with 5 operands in modify_call_for_omp_dispatch, at gimplify.cc:3969
   14 |   S{}.b(42);
  |   ^

I noticed this while preparing my PR119659 patch for submission,
it's right around the same area, similar cause
This will be fixed alongside that patch.

[Bug c++/119602] [OpenMP] append_args dependent prefer_type uses value from first instantiation in all instantiations

2025-04-24 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119602

--- Comment #1 from Alex  ---
I somehow botched the test case in my original post,
here is the fixed version.
https://godbolt.org/z/no9Pbv78K
```
typedef enum omp_interop_t : __UINTPTR_TYPE__
{
  omp_interop_none = 0
} omp_interop_t;

typedef enum omp_interop_fr_t
{
  omp_ifr_cuda = 1,
  omp_ifr_cuda_driver = 2,
  omp_ifr_opencl = 3,
  omp_ifr_sycl = 4,
  omp_ifr_hip = 5,
  omp_ifr_level_zero = 6,
  omp_ifr_hsa = 7,
  omp_ifr_last = omp_ifr_hsa
} omp_interop_fr_t;

template
struct FR {};

template
void v_dependent_fr(FR x, T2 y) { }

#pragma omp declare variant(v_dependent_fr) match(construct={dispatch}) \
append_args(interop(target, \
   
prefer_type(V)))
template
void b_dependent_fr(FR x) { }


template
void v_cuda(T x, T2 y) { }

#pragma omp declare variant(v_cuda) match(construct={dispatch}) \
append_args(interop(target, \
   
prefer_type(omp_ifr_cuda_driver)))
template
void b_cuda(T x) { }


template
void v_hip(T x, T2 y) { }

#pragma omp declare variant(v_hip) match(construct={dispatch}) \
   append_args(interop(target, \
  
prefer_type(omp_ifr_hip)))
template
void b_hip(T x) { }


template
void v_hsa(T x, T2 y) { }

#pragma omp declare variant(v_hsa) match(construct={dispatch}) \
   append_args(interop(target, \
  
prefer_type(omp_ifr_hsa)))
template
void b_hsa(T x) { }

void f ()
{
  #pragma omp dispatch
  b_dependent_fr (FR{});

  #pragma omp dispatch
  b_dependent_fr (FR{});

  #pragma omp dispatch
  b_dependent_fr (FR{});

  #pragma omp dispatch
  b_dependent_fr (FR{});

  #pragma omp dispatch
  b_cuda (0);

  #pragma omp dispatch
  b_hip (0);

  #pragma omp dispatch
  b_hsa (0);
}
```

[Bug middle-end/120021] Offloading vs. C++ 'std::initializer_list'

2025-04-30 Thread waffl3x at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120021

Alex  changed:

   What|Removed |Added

Summary|Offloading vs. C++  |Offloading vs. C++
   |'std::valarray' |'std::initializer_list'
 CC||waffl3x at gcc dot gnu.org

--- Comment #3 from Alex  ---
This appears to be related to std::initializer_list
```
#include 

bool initializer_list()
{
  int sum;
  #pragma omp target map(from: sum)
{
  auto il = {0, 1, 2, 3, 4, 5};
  int n = 0;
  auto end = il.end();
  for (auto it = il.begin(); it != end; ++it)
n += *it;
  sum = n;
}
  return sum == 15;
}

int main()
{
  return initializer_list() ? 0 : 1;
}
```
I'm sure a better reduced case exists, seems specifically be reading the
elements of the list as the following passes.
```
/* std::initializer_list in target region.  */

#include 

bool initializer_list()
{
  bool ok;
  #pragma omp target map(from: ok)
{
  auto il = {0, 1, 2, 3, 4, 5};
  ok = il.begin() != il.end();
}
  return ok;
}

int main()
{
  return initializer_list() ? 0 : 1;
}
```