On 10/29/25 7:55 PM, Kito Cheng wrote:
The RISC-V ABI currently defines that empty unions and zero length array
in struct should be ignored, but the implementation in GCC is not
correct.

e.g. for the following code:
```
struct S2eu_2f {
     union{} e1;
     float f;
     float g;
};
```

The RISC-V ABI defines that the layout of S2eu_2f should be equivalent
to:
```
struct S2eu_2f {
        float f;
        float g;
};
```

However, the current GCC implementation passes S2eu_2f in a0 (lp64d)
rather than fa0 and fa1 (lp64d).

Also for the following code:
```
struct S0ae_2f {
     struct{} e1[0];
     float f;
     float g;
};
```
The RISC-V ABI defines that the layout of S0ae_2f should be equivalent
to:
```
struct S0ae_2f {
        float f;
        float g;
};
```

And again, the current GCC implementation passes S0ae_2f in a0 (lp64d)
rather than fa0 and fa1 (lp64d).

This patch fixes the issue by updating the relevant functions to correctly
handle empty unions, also we have implemented the ABI change warning to
notify user that the ABI of empty unions and zero length array in struct
has been changed/fixed.

Generally ABI should not be changed, but the psABI is defined there for
long time and clang/LLVM has already implemented it correctly, so we
decide to fix it in GCC as well to maintain compatibility, and another
reason to fix that in GCC is zero length array and empty union in struct
should be rarely used in practice, so the impact should be limited.

References:
[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/464

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_flatten_aggregate_field): Skip
        empty unions and zero-length arrays when flattening aggregate
        fields for ABI classification.
        (riscv_pass_aggregate_in_fpr_pair_p): Refactor to use separate
        field parsing and emit ABI change warning for affected types.
        (riscv_pass_aggregate_in_fpr_and_gpr_p): Likewise.

gcc/testsuite/ChangeLog:

        * g++.target/riscv/abi/empty-struct+union-1.cc: New test.
        * g++.target/riscv/abi/empty-struct+union-2.cc: New test.
        * g++.target/riscv/abi/empty-struct+union-3.cc: New test.
        * g++.target/riscv/abi/empty-struct+union-4.cc: New test.
        * g++.target/riscv/abi/empty-struct-1.cc: New test.
        * g++.target/riscv/abi/empty-struct-2.cc: New test.
        * g++.target/riscv/abi/empty-struct-3.cc: New test.
        * g++.target/riscv/abi/empty-struct-4.cc: New test.
        * g++.target/riscv/abi/empty-struct-5.cc: New test.
        * g++.target/riscv/abi/empty-struct-6.cc: New test.
        * g++.target/riscv/abi/empty-struct-7.cc: New test.
        * g++.target/riscv/abi/empty-struct-8.cc: New test.
        * g++.target/riscv/abi/empty-struct-9.cc: New test.
        * g++.target/riscv/abi/empty-struct-10.cc: New test.
        * g++.target/riscv/abi/empty-struct-11.cc: New test.
        * g++.target/riscv/abi/empty-struct-12.cc: New test.
        * g++.target/riscv/abi/empty-union-1.cc: New test.
        * g++.target/riscv/abi/empty-union-2.cc: New test.
        * g++.target/riscv/abi/empty-union-3.cc: New test.
        * g++.target/riscv/abi/empty-union-4.cc: New test.
        * g++.target/riscv/riscv.exp: Add abi subdirectory.
        * gcc.target/riscv/abi/empty-struct+union-1.c: New test.
        * gcc.target/riscv/abi/empty-struct+union-2.c: New test.
        * gcc.target/riscv/abi/empty-struct+union-3.c: New test.
        * gcc.target/riscv/abi/empty-struct+union-4.c: New test.
        * gcc.target/riscv/abi/empty-struct-1.c: New test.
        * gcc.target/riscv/abi/empty-struct-2.c: New test.
        * gcc.target/riscv/abi/empty-struct-3.c: New test.
        * gcc.target/riscv/abi/empty-struct-4.c: New test.
        * gcc.target/riscv/abi/empty-struct-5.c: New test.
        * gcc.target/riscv/abi/empty-struct-6.c: New test.
        * gcc.target/riscv/abi/empty-struct-7.c: New test.
        * gcc.target/riscv/abi/empty-struct-8.c: New test.
        * gcc.target/riscv/abi/empty-struct-9.c: New test.
        * gcc.target/riscv/abi/empty-struct-10.c: New test.
        * gcc.target/riscv/abi/empty-struct-11.c: New test.
        * gcc.target/riscv/abi/empty-struct-12.c: New test.
        * gcc.target/riscv/abi/empty-union-1.c: New test.
        * gcc.target/riscv/abi/empty-union-2.c: New test.
        * gcc.target/riscv/abi/empty-union-3.c: New test.
        * gcc.target/riscv/abi/empty-union-4.c: New test.
        * gcc.target/riscv/riscv.exp: Add abi subdirectory.
So the target_attr-06 failures are not related to this patch, so we can set those aside.

And yes, I'd agree this is just a bug and we should fix it and probably document it in the release notes for gcc-16 (which don't exist yet).

OK for the trunk. I'd lean slightly against adjusting gcc-15 but if you felt strongly we should adjust gcc-15 I could be convinced that a backport is warranted (in which case I'd very much like to see a bug raised so that it gets onto the list of issues we'll touch on in the release notes for gcc-15 as well).

Somewhat related, do we have plans (or have we already handled) _BitInt? That's PR 117581.

jeff



Reply via email to