On 6/16/26 2:28 PM, Thomas Schwinge wrote:
Hi!

Jason, hopfully you'll be able to help with my question, please see
below.

Arsen, I've added you as you recently happened to work on a GCC/GCN issue
involving named address spaces, and maybe generally are able to help with
this C++ issue here.

For reference, this is in context of the last patch submission:
<https://inbox.sourceware.org/[email protected]>
"[REBASED] [PATCH v4] c++: parser - Support for target address spaces in C++".

On 2026-05-21T21:51:09-0400, Jason Merrill <[email protected]> wrote:
On 5/15/26 8:17 AM, Thomas Schwinge wrote:
If we get a general "go", I'll then offer to fix up a few places for GCC
coding style conformance (so please don't review for that, yet)

(Still to be done.)

and I'll
work on test cases some more.

(I've got a few more lined up.)

I'll also examine if, since then, any new
code has appeared where 'ADDR_SPACE_CONVERT_EXPR' needs to be handled.

(Still to be done.)

PR69549 "Named Address Spaces does not compile in C++" is going to be
resolved by this patch, so should get referenced in the Git log.

On 2022-11-10T16:42:22+0100, Paul Iannetta <[email protected]> wrote:
It took a bit of time to rework the rough corners.  I tried to be
mirror as much as possible the C front-end, especially when it comes
to implicit conversions [...]

I just found one case where the C and C++ front ends behave differently;
please help me understand the desired behavior in C++ language as well as
GCC/C++ front end implementation.

This is not relevant for x86's '__seg_fs', '__seg_gs', but consider, for
example, the case of GCC/GCN, which has:

'gcc/config/gcn/gcn.h':

     /* Address spaces.  */
     enum gcn_address_spaces
     {
       ADDR_SPACE_DEFAULT = 0,
       ADDR_SPACE_FLAT,
     [...]
       ADDR_SPACE_LDS,
     [...]
     };
     #define REGISTER_TARGET_PRAGMAS() do {                               \
       c_register_addr_space ("__flat", ADDR_SPACE_FLAT);                 \
     [...]
       c_register_addr_space ("__lds", ADDR_SPACE_LDS);                   \
     [...]
     } while (0);
     [...]

'gcc/config/gcn/gcn.cc':

     /* Implement TARGET_ADDR_SPACE_SUBSET_P.
Determine if one named address space is a subset of another. */ static bool
     gcn_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
     {
       if (subset == superset)
         return true;
       /* FIXME is this true?  */
       if (AS_FLAT_P (superset) || AS_SCALAR_FLAT_P (superset))
         return true;
       return false;
     }

..., and, for example, the test case
'gcc.target/gcn/addr-space-convert-1.c':

     void __flat *
     convert_lds_addr (void __lds *x)
     { return x; }
/* { dg-final { scan-assembler "shared_base" } } */

This means, per my not-too-in-depth knowledge of GCC/GCN back end
details, that there is a way to convert from '__lds' to '__flat', and per
'gcc/config/gcn/gcn.cc:gcn_addr_space_convert', this needs to emit some
code involving a 'SHARED_BASE_REG' ('shared_base' checked in the test
case).  (Details not important here.)  For this code path to be invoked,
we need a 'ADDR_SPACE_CONVERT_EXPR' ('gcc/expr.cc:expand_expr_real_2').

For GCC/C as well as GCC/C++ (with the current implementation, referenced
above), that works fine for the test case
'gcc.target/gcn/addr-space-convert-1.c'; we get '-fdump-tree-gimple-raw':

     <address-space-1> void * convert_lds_addr (<address-space-4> void * x)
     gimple_bind <
       <address-space-1> void * D.2346;
gimple_assign <addr_space_convert_expr, D.2346, x, NULL, NULL>
       gimple_return <D.2346>
     >

A variant where we use an explicit cast, as in:

      void __flat *
      convert_lds_addr (void __lds *x)
     -{ return x; }
     +{ return (void __flat *) x; }

..., for GCC/C that likewise works fine (Arsen, that is the expected
behavior, correct?), but for GCC/C++, we get:

     -  gimple_assign <addr_space_convert_expr, D.2346, x, NULL, NULL>
     +  gimple_assign <nop_expr, D.2346, x, NULL, NULL>

..., and therefore don't get 'shared_base' via 'gcn_addr_space_convert'.
(See below for my current understand where/why that happens.)

Jason, Arsen, is my understanding correct that GCC/C++ should complile
the code with C-style cast (or 'return const_cast<void __flat *>(x);',
for that matter), in the same way as in the case of an implicit cast?
That is, all these different source code variants mentioned above are
well-defined and should behave in the same way?

That certainly seems like a missed-case bug.

 From Paul's email:

    4. I left untouched same_type_ignoring_top_level_qualifiers_p, even
    though that was very convenient and often lead to better error
    messages since error were caught earlier.

(Might well be relevant, but I've not yet looked into that one.)  But:

    5. The handling of conversions is done very late in the calling
    chain, because I absolutely want to fold the conversion and force
    the conversion to appear as an ADDR_SPACE_CONV_EXPR after
    gimplification.

That certainly is relevant here.  (See below.)

Now, queue to a review comment by Jason (thanks!):

        * call.cc (convert_like_internal): Add support for implicit
          conversion between compatible address spaces.  This is done
          here (and not in a higher caller) because we want to force the
          use of cp_fold_convert, which later enable back-end writers to
          tune-up the fine details of the conversion.

(That's directly related to Paul's "5." mentioned just above.)

This kind of explanation belongs in a code comment rather than the
ChangeLog.

(ACK; moved.)

This comment suggests that we want to support these conversions

(That's the test case/behavior I've discussed above.)

but the
change is to the part of the function that handles "bad" conversions.  I
would expect handling of conversions we want to support to go in the
ck_ptr case near the bottom of the function.

That suggestion doesn't (easily) work, as we'll then run into:

     complained = permerror (&richloc,
                             "invalid conversion from %qH to %qI",
                             TREE_TYPE (expr), totype);

So we're wrongly setting bad_p on a conversion that isn't actually bad.

But maybe that handling here generally isn't completely right?  Also
relevant should be the following remark:

I was surprised that no change to standard_conversion was needed, but I
guess the change to comp_ptr_ttypes_real covers that.

(apparently not yet)

(I've not yet looked in detail into 'comp_ptr_ttypes_real'.)  But let's
look at 'gcc/cp/call.cc:standard_conversion', in context of the test case
discussed above.  For the implicit cast, we take the following code path:

     [...]
     else if (ptr_reasonably_similar (to_pointee, from_pointee))
       {
         conv = build_conv (ck_ptr, to, conv);
         conv->bad_p = true;
       }

..., and then, instead of emitting an error due to 'conv->bad_p',
'convert_like_internal' "fixes this up" (via enforced 'cp_fold_convert'):

     else if (t->kind == ck_ptr
     [...]
             if (addr_space_superset (as_from, as_to, &as_common)
                 && as_common == as_to)
               return cp_fold_convert (totype, expr);

However, in the case of the explicit cast ('return (void __flat *) x;'),
we take the following code path in 'gcc/cp/call.cc:standard_conversion':

     [...]
     else if (c_cast_p && comp_ptr_ttypes_const (to, from, bounds_either))
       /* In a C-style cast, we ignore CV-qualification because we
          are allowed to perform a static_cast followed by a
          const_cast.  */
       conv = build_conv (ck_qual, to, conv);

Note 'ck_qual' instead of 'ck_ptr', and no 'conv->bad_p = true;', and
therefore neither 'convert_like_internal' nor anything else does the
'cp_fold_convert' (or whatever else) to get the necessary
'ADDR_SPACE_CONVERT_EXPR'.

I would also expect compare_ics to have an opinion about such
conversions vs conversions within the same address space.

(Have not yet looked into that, either.)

To (properly) handle those implicit/explicit conversions, instead of the
proposed 'convert_like_internal' changes, do we maybe handle that in
'gcc/cp/call.cc:standard_conversion', maybe similar to:

      if (same_type_p (from, to))
        /* OK */;
     +else if (some_new_addr_space_conv_p ([...])) // irregardless of 'c_cast_p'
     +  conv = build_conv (ck_[...], to, conv);

Does that make any sense?  Would this be 'ck_ptr' or another existing
one, or maybe even require a new code?

ck_qual vs ck_ptr is a bit of a question, whether these conversions should fit into the C++ conversion model as a qualification conversion or pointer conversion. I think ck_qual is the better fit, since they don't change the pointed-to type. So we want to get ck_qual for (valid) implicit conversions as well as casts.

Given that, I think handling this in comp_ptr_ttypes_real still makes sense, rather than adding an additional case in standard_conversion. It seems that hunk just isn't right yet.

How do we (properly) request an
'ADDR_SPACE_CONVERT_EXPR' to be generated, be it indeed via
'cp_fold_convert' or something else?

For a ck_qual, convert_like_internal ends up calling cp_convert -> ocp_convert -> cp_convert_to_pointer. It seems this last function needs updating to not assume it can express all conversions between pointers to the same type with build_nop.

Jason

As you can easily tell, I'm currently quite lost in the GCC/C++ front end
code, to figure out where this should be handled, and how.  Will gladly
take pointers.


Grüße
  Thomas

Reply via email to