On Tue, Aug 26, 2025 at 12:26:17AM +0200, Jakub Jelinek wrote:
> Unfortunately that version (unlike the previous one) regresses:
...
> UNRESOLVED: std/ranges/access/rend.cc  -std=gnu++26 compilation failed to 
> produce executable
> 
> Will try to investigate what's going on tomorrow^H^H^Htoday.

Took a while to reduce, -std=c++2{0,3,6}:

template <typename T>
struct remove_reference { using type = __remove_reference (T); };
template <typename> bool A;
template <typename T> constexpr bool A<T &> = true;
template <typename T> void foo (typename remove_reference <T>::type);
template <typename T, typename U>
concept B = requires (T x, U) { x; };
template <typename T, typename U>
concept C = B<T, U>;
template <typename T>
concept D = A<T>;
struct E {};
template <typename T>
concept F = requires (T &x) { { 0 } -> C<decltype (E {} (foo<T> (x)))>; };
template <typename T>
concept G = requires(T &x) { { x } -> C<decltype (E {} (foo<T> (x)))>; };
struct H {
  template <D T>
  void operator () (T &&) { if (F<T>) if (G<T>) ; }
} h;
struct I {};

void
bar ()
{
  I r;
  h (r);
}

When current_function_decl is the H::operator (), the PARM_DECL x
from concept F = requires (T &x) has NULL DECL_CONTEXT for which
uses_template_parms returns false, so with:
+             /* Parameters of non-templates map to themselves (e.g. in
+                expansion statement body).  */
+             if (!uses_template_parms (DECL_CONTEXT (t)))
+               RETURN (t);
+
we return t rather than doing what we were before:
              /* This can happen for a parameter name used later in a function
                 declaration (such as in a late-specified return type).  Just
                 make a dummy decl, since it's only used for its type.  */
              gcc_assert (cp_unevaluated_operand);
              r = tsubst_decl (t, args, complain);
              /* Give it the template pattern as its context; its true context
                 hasn't been instantiated yet and this is good enough for
                 mangling.  */
              DECL_CONTEXT (r) = DECL_CONTEXT (t);
Now, in expansion stmt bodies we can have unevaluated operands, so doing
              if (cp_unevaluated_oeprand)
                {
                  r = tsubst_decl (t, args, complain);
                  DECL_CONTEXT (r) = DECL_CONTEXT (t);
                }
              else if (!uses_template_parms (DECL_CONTEXT (t)))
                RETURN (t);
              else
                gcc_unreachable ();
would be wrong.  Guess
              if (DECL_CONTEXT (t)
                  && !uses_template_parms (DECL_CONTEXT (t)))
                RETURN (t);
would fix these ICEs, shall I go with that, or the original expansion stmt
body check, or something else?

        Jakub

Reply via email to