Issue 175486
Summary [Clang] `APPLE` specific ABI Issue with Reuse of Tail Padding
Labels clang
Assignees
Reporter NekrozQliphort
    This may act as a follow-up on [Bug 16537 - ABI issue with the C++11 definition of POD and tail padding](https://bugs.llvm.org/show_bug.cgi?id=16537), but it is currently reproducible on `homebrew/clang` (`apple-clang` should also have the same issue). Below I have attached the test case:
```cpp
// Compiled with clang++ --std=c++23
#include <stdio.h>

typedef unsigned long long int64;
typedef unsigned char int8;

// non-POD in 03
struct pod_in_11_only {
private:
  int64 x;
};
 
// non-POD in 03
struct tail_padded_pod_in_11_only {
  pod_in_11_only pod11;
  int8 tail_padding;
};

struct might_use_tail_padding : public tail_padded_pod_in_11_only {
  int8 may_go_into_tail_padding;
};

int main() {
    printf("sizeof(might_use_tail_padding) == %lu\n", sizeof(might_use_tail_padding));
    printf("%s\n", sizeof(might_use_tail_padding) == 16 ? "Using tail padding"
 : "NOT using tail padding");
 return 0;
}
```
This case as of now, on **Homebrew clang version 21.1.8** still does not reuse the tail padding, which is at odds with the [Itanium C++ ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#POD). 
> There have been multiple published revisions to the ISO C++ standard, and each one has included a different definition of POD. To ensure interoperation of code compiled according to different revisions of the standard, it is necessary to settle on a single definition for a platform. A platform vendor may choose to follow a different revision of the standard, but by default, the definition of POD under this ABI is the definition from the 2003 revision (TC1).

The difference seems to stem from the difference of POD definition used when determining the layout. After tweaking the test case so that it is no longer a POD by the C++11 definition, this reuses the tail-padding as expected.
```cpp
// Compiled with clang++ --std=c++23

#include <stdio.h>

typedef unsigned long long int64;
typedef unsigned char int8;

// POD in 11
struct pod_in_11 {
  ~pod_in_11() {}
private:
 int64 x;
};
 
// POD in 11
struct tail_padded_pod_in_11 {
  pod_in_11 pod11;
  int8 tail_padding;
};
 
struct might_use_tail_padding : public tail_padded_pod_in_11 {
  int8 may_go_into_tail_padding;
};

int main() {
    printf("sizeof(might_use_tail_padding) == %lu\n", sizeof(might_use_tail_padding));
    printf("%s\n", sizeof(might_use_tail_padding) == 16 ? "Using tail padding"
 : "NOT using tail padding");
 return 0;
}
```
I suspect this is also why the behaviour of the following code differs (does not reuse tail padding on `homebrew/clang`):
```cpp
// Compiled with clang++ --std=c++23
struct AllowOverlapMixin {};

struct Foo: AllowOverlapMixin {
    long long foo_val;
    bool foo_val2;
};

template <typename T>
struct MaybeDeleted {
 [[no_unique_address]] T val;
    bool deleted;
};

static_assert(sizeof(Foo) == 16);
static_assert(alignof(Foo) == 8);
static_assert(sizeof(MaybeDeleted<Foo>) == 16); // 24 on homebrew/clang, does not compile
```

Here are the details of the running environment if needed.
```
$ clang++ --version          
Homebrew clang version 21.1.8
Target: arm64-apple-darwin22.4.0
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/llvm/21.1.8/bin
Configuration file: /opt/homebrew/etc/clang/arm64-apple-darwin22.cfg

$ sysctl -n machdep.cpu.brand_string
Apple M1 Pro 
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to