Am 15.05.26 um 15:11 schrieb Paul IANNETTA:
On Friday, May 15, 2026 at 09:17:14 PM GMT+9, Thomas Schwinge <[email protected]> wrote:

[Note that emails to <[email protected]> bounce; please use Paul's
other email address: <[email protected]>.]

Hi!

I'd like to resume this patch submission here, which is adding support
for named address spaces to GNU C++, as is implemented for GNU C. As far
as I can tell, there wasn't any specific technical reason that this patch
review stalled, back then, in 2022-11? (Jason?)

I've now rebased this onto recent GCC trunk, see attached
'0001-c-parser-Support-for-target-address-spaces-in-C.patch'. There were
just a few merge conflicts that I had to fix up (nothing serious), and
I've bootstrap-tested on x86_64-pc-linux-gnu (only, so far).

Hi Paul,

I have one test case where the generated code for avr is not correct:

int func1 (int x)
{
    static const __flash int arr[] = { 123, 456 };
    return arr[x];
}

The code should read from AS1 but reads from generic space.

$ avr-g++ -S -Os as.cpp -v

Target: avr
Configured with: ../../source/gcc-master/configure --target=avr --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 17.0.0 20260615 (experimental) (GCC)

Apart from that, better dumping would be nice to have:

Take for example this function for which correct code is
generated:

int func2 (const __flash int *p, int x)
{
    return p[x];
}

With -fdump-tree-optimized the respective dump file reads:

;; Function func2 (_Z5func2PU7__flashKii, funcdef_no=1, decl_uid=2281, cgraph_uid=3, symbol_order=2)

int func2 (const <address-space-1> int * p, int x)
{
  unsigned int x.0_1;
  unsigned int _2;
  const <address-space-1> int * _3;
  int _7;

  <bb 2> [local count: 1073741824]:
  x.0_1 = (unsigned int) x_4(D);
  _2 = x.0_1 * 2;
  _3 = p_5(D) + _2;  <-- uses AS1
  _7 = *_3;          <-- uses AS1
  return _7;
}

So the dump could show more of the involved non-generic ASes.

Then I have some trouble with constructors:

struct SS { int val; };

const __flash SS ss[] = { 123, 456 };

SS read_ss (int x)
{
    return ss[x];
}

as.cpp: In function 'SS read_ss(int)':
as.cpp:10:16: error: no matching function for call to 'SS(const __flash SS&)'
   10 |     return ss[x];
      |            ~~~~^
  • there are 3 candidates
    • candidate 1: 'constexpr SS::SS(const SS&)' (near match)
      as.cpp:1:8:
          1 | struct SS
            |        ^~
      • conversion of argument 1 would be ill-formed:
• error: binding reference of type 'const SS&' to 'const __flash SS' discards qualifiers
        as.cpp:10:16:
           10 |     return ss[x];
              |            ~~~~^
    • candidate 2: 'constexpr SS::SS(SS&&)' (near match)
      as.cpp:1:8:
          1 | struct SS
            |        ^~
      • conversion of argument 1 would be ill-formed:
• error: cannot bind rvalue reference of type 'SS&&' to lvalue of type 'const __flash SS'
        as.cpp:10:16:
           10 |     return ss[x];
              |            ~~~~^
    • candidate 3: 'constexpr SS::SS()'
      as.cpp:1:8:
          1 | struct SS
            |        ^~
      • candidate expects 0 arguments, 1 provided

Shouldn't there be a default constructor that reads from AS1?
At least when the class is trivially copyable?
And adding a qualified constructor doesn't work either:

struct SS
{
    SS (const __flash SS &ss) : val(ss.val) {}
    SS (int i) const __flash : val(i) {}
    int val;
};

as.cpp:4:22: error: constructors may not be cv-qualified
    4 |     SS (int i) const __flash : val(i) {}
      |                      ^~~~~~~


Notice that a non-qualified constructor will pop a static
constructor function that writes to __flash, which is invalid
because __flash cannot be changed after load time.

Johann

The 'gcc/targhooks.cc:default_addr_space_subset_p' change that appeared
in this v4:

bool
default_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
{
- return (subset == superset);
+ return (subset == 2 && superset == 0) || (subset == superset);
}

... is entirely unmotivated, as far as I can tell: probably a local hack
for testing, that sneaked into the patch posted? This change regresses
'gcc.target/i386/addr-space-typeck-1.c' (notice: C test case), which
again PASSes with that change undone.

The new test case 'g++.dg/template/spec-addr-space.C' needs minor
adjusting per changed GCC diagnostics (not related to the new named
addess space support):

@@ -1,8 +1,9 @@
// { dg-do compile { target { i?86-*-* x86_64-*-* } } }

template <class T>
-int f (T __seg_gs *p) { return *p; } // { dg-note "candidate: 'template<class T> int f.__seg_gs T\*." } +int f (T __seg_gs *p) { return *p; } // { dg-note "candidate 1: 'template<class T> int f.__seg_gs T\*." } // { dg-note "template argument deduction/substitution failed:" "" { target *-*-* } .-1 }
__seg_fs int *a;
int main() { f(a); } // { dg-error "no matching" }
-// { dg-note "types .__seg_gs T. and .__seg_fs int. have incompatible cv-qualifiers" "" { target *-*-* } .-1 }
+// { dg-note "there is 1 candidate" "" { target *-*-* } .-1 }
+// { dg-note "types .__seg_gs T. and .__seg_fs int. have incompatible cv-qualifiers" "" { target *-*-* } .-2 }

With that, all new test cases PASS, and no regressions.

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), and I'll
work on test cases some more. I'll also examine if, since then, any new
code has appeared where 'ADDR_SPACE_CONVERT_EXPR' needs to be handled.

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.

Full-quote of Paul's email from back then:

On 2022-11-10T16:42:22+0100, Paul Iannetta <[email protected]> wrote:
 > Hi,
 >
 > 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, and warnings; and expose the same hooks as
 > the C front-end does. The C++ front-end produces as much warnings
 > that the C front-end, however they are sometimes a bit less
 > informative (especially so, when passing arguments to functions).
 >
 > I also address the following points:
 >
 > 1. The handling of the register storage class is grouped with the
 > other variables with automatic storage. This incurs a slight
 > dis-alignment since you cannot have global register variables do not
 > trigger an error, only a warning.
 >
 > 2. In template unification, I maintain that we don't want any
 > changes to address spaces whatsoever during the unification process,
 > hence ignoring the strict flag. Nevertheless, we allow implicit
 > conversion, and I have verified that, indeed,
 >
 >
 > template <class T> void f(T **);
 > struct A {
 > template <class T> operator T*__seg_fs*();
 > };
 > int main()
 > {
 > f((void* __seg_fs *)0); // (1): void*__seg_fs* -> void** should be OK
 > void (*p)(void * __seg_fs *) = f; // (2): error
 > }
 >
 > works as intended. That is, (1) works if we set __seg_fs as a subspace
 > of the generic address space, and (2) is always an error.
 >
 > 3. In template unification, when unifying __as1 T = __as2 U we want
 > to unify to the __as1 at most, never to __as2 at most, because the
 > function requiring __as1 T may want to mix address space from the
 > bigger address space, therefore I think that we want to have the
 > smaller address-space to be unified into the bigger of the two.
 >
 > 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.
 >
 > 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.
 >
 > 6. Currently, I do not handle classes. I see what I can do in a
 > further revision and maybe add a target hook to hand down to targets
 > the choice of the address space of the vtable.
 >
 > 7. This can't be added as a test case, but I checked that:
 >
 > // In this test case, __seg_gs is a subset of the generic address
 > // space.
 >
 > int f (int *);
 > int main ()
 > {
 > int __seg_fs *pa;
 > int __seg_gs *pb;
 > int *pc;
> pa = (__seg_fs int *) pb; return *pa; // warning: cast to ‘__seg_fs’ address space pointer from disjoint ‘__seg_gs’ address space pointer > pa = (int __seg_fs *) pc; return *pa; // warning: cast to ‘__seg_fs’ address space pointer from disjoint generic address space pointer > pa = pb; return *pa; // error: invalid conversion from ‘__seg_gs int*’ to ‘__seg_fs int*’ > pc = pb; return *pc; // __seg_gs int * -> int * converted through ADDR_SPACE_CONV_EXPR > pb = pc; return *pb; // error: invalid conversion from ‘int*’ to ‘__seg_gs int*’ > pc = pa; return *pb; // error: invalid conversion from ‘__seg_fs int*’ to ‘int*’ > return f (pb); // __seg_gs int * -> int * converted through ADDR_SPACE_CONV_EXPR > // return f (pa); // error: invalid conversion from ‘__seg_fs int*’ to ‘int*’
 > // note: initializing argument 1 of ‘int f(int*)’
 > }
 >
 > Thanks,
 > Paul
 >
 > Rebased on current trunk, bootstrapped and regtested.

Hi,

Thank you for taking the time to rebase this patch on trunk. I've compared your rebased patch to my local version and I did not spot
any significant differences.

Concerning, 'gcc/targhooks.cc:default_addr_space_subset_p', I confirm.
This is a spurious change, and it does not appear in my local tree.

Paul

Reply via email to