Hello,

First attempt at contributing to GCC. My GCC knowledge is limited so any
assistance would be appreciated.

I have tried to implement a `trivial_abi` attribute for GCC because I ran
into an issue interacting with clang built code where `trivial_abi` was in
use. Without implementing the same attribute the same way, we risk having
nuanced calling convention mismatches.

There also has been a long standing feature request
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107187

I have attempted to get the patch accepted by the formatter. However, I
didn't fix the one remaining "There should be exactly one space between
function name and parenthesis." following the code surrounding my change.

Yuxuan
From a14881a229ed51a570958bf8d1af3cb53a5a1277 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <[email protected]>
Date: Tue, 7 Oct 2025 14:17:35 -0700
Subject: [PATCH] implement trivial_abi

---
 gcc/cp/class.cc                               |   4 +-
 gcc/cp/cp-tree.h                              |  10 +-
 gcc/cp/module.cc                              |   2 +
 gcc/cp/pt.cc                                  |   2 +
 gcc/cp/tree.cc                                | 159 ++++++++++++++++++
 .../g++.dg/cpp0x/attr-trivial_abi1.C          |  35 ++++
 .../g++.dg/cpp0x/attr-trivial_abi2.C          |  49 ++++++
 .../g++.dg/cpp0x/attr-trivial_abi3.C          |  51 ++++++
 .../g++.dg/cpp0x/attr-trivial_abi4.C          |  69 ++++++++
 .../g++.dg/cpp0x/attr-trivial_abi5.C          |  72 ++++++++
 10 files changed, 450 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi5.C

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index b56cc518a11..549a4b16630 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -2415,8 +2415,8 @@ finish_struct_bits (tree t)
      mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
      nonzero.  This will cause it to be passed by invisible reference
      and prevent it from being returned in a register.  */
-  if (type_has_nontrivial_copy_init (t)
-      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+  if (!trivial_for_calls_p (t) && (type_has_nontrivial_copy_init (t)
+      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)))
     {
       SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
       SET_TYPE_MODE (t, BLKmode);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6ee945f3ebf..a35696c8a36 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2527,6 +2527,8 @@ struct GTY(()) lang_type {
   bool replaceable : 1;
   bool replaceable_computed : 1;
 
+  bool has_trivial_abi : 1;
+
   /* When adding a flag here, consider whether or not it ought to
      apply to a template instance if it applies to the template.  If
      so, make sure to copy it in instantiate_class_template!
@@ -2536,7 +2538,7 @@ struct GTY(()) lang_type {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 30;
+  unsigned dummy : 29;
 
   tree primary_base;
   vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2906,7 +2908,12 @@ struct GTY(()) lang_type {
    already.  */
 #define CLASSTYPE_REPLACEABLE_COMPUTED(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->replaceable_computed)
+
+/* True if the class is trivial for the purpose of calls.  */
+#define CLASSTYPE_HAS_TRIVIAL_ABI(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->has_trivial_abi)
 
+
 /* Additional macros for inheritance information.  */
 
 /* Nonzero means that this class is on a path leading to a new vtable.  */
@@ -8371,6 +8378,7 @@ extern bool trivial_type_p			(const_tree);
 extern bool trivially_relocatable_type_p	(tree);
 extern bool replaceable_type_p			(tree);
 extern bool trivially_copyable_p		(const_tree);
+extern bool trivial_for_calls_p			(const_tree);
 extern bool type_has_unique_obj_representations (const_tree);
 extern bool scalarish_type_p			(const_tree);
 extern bool structural_type_p			(tree, bool = false);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index be873c19295..0404be19435 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6209,6 +6209,7 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
 
   WB (lang->replaceable);
   WB (lang->replaceable_computed);
+  WB (lang->has_trivial_abi);
 #undef WB
 }
 
@@ -6287,6 +6288,7 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
 
   RB (lang->replaceable);
   RB (lang->replaceable_computed);
+  RB (lang->has_trivial_abi);
 #undef RB
   return !get_overrun ();
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bd60d515653..9597f2aacb8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12727,6 +12727,8 @@ instantiate_class_template (tree type)
 	= CLASSTYPE_REPLACEABLE_BIT (pattern);
       CLASSTYPE_REPLACEABLE_COMPUTED (type)
 	= CLASSTYPE_REPLACEABLE_COMPUTED (pattern);
+      CLASSTYPE_HAS_TRIVIAL_ABI (type)
+	= CLASSTYPE_HAS_TRIVIAL_ABI (pattern);
     }
 
   pbinfo = TYPE_BINFO (pattern);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 03b58ff6005..929746fc95a 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -48,6 +48,7 @@ static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
 static tree handle_contract_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_dangling_attribute (tree *, tree, tree, int, bool *);
+static tree handle_trivial_abi_attribute (tree *, tree, tree, int, bool *);
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  */
@@ -4796,6 +4797,21 @@ trivial_type_p (const_tree t)
     return scalarish_type_p (t);
 }
 
+/* Returns 1 iff type T is trivial for the purpose of calls.
+   This includes types that are otherwise trivial, or types
+   that have the trivial_abi attribute.  */
+
+bool
+trivial_for_calls_p (const_tree t)
+{
+  t = strip_array_types (CONST_CAST_TREE (t));
+
+  if (trivial_type_p (t))
+    return true;
+
+  return CLASSTYPE_HAS_TRIVIAL_ABI (t);
+}
+
 /* Returns 1 iff type T is a default-movable type, as defined in
    [class.prop].  */
 
@@ -4923,6 +4939,14 @@ trivially_relocatable_type_p (tree t)
   if (!COMPLETE_TYPE_P (t))
     return false;
 
+  /* trivial_abi attribute makes the class trivially relocatable.  */
+  if (CLASSTYPE_HAS_TRIVIAL_ABI (t))
+    {
+      CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) = 1;
+      CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1;
+      return true;
+    }
+
   if (!CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t)
       && !union_with_no_declared_special_member_fns (t)
       && !default_movable_type_p (t))
@@ -5602,6 +5626,8 @@ static const attribute_spec cxx_gnu_attributes[] =
     handle_abi_tag_attribute, NULL },
   { "no_dangling", 0, 1, false, true, false, false,
     handle_no_dangling_attribute, NULL },
+  { "trivial_abi", 0, 0, false, true, false, true,
+    handle_trivial_abi_attribute, NULL },
 };
 
 const scoped_attribute_specs cxx_gnu_attribute_table =
@@ -5933,6 +5959,139 @@ handle_no_dangling_attribute (tree *node, tree name, tree args, int,
   return NULL_TREE;
 }
 
+/* Handle a "trivial_abi" attribute.  */
+
+static tree
+handle_trivial_abi_attribute (tree *node, tree name, tree, int
+			      bool *no_add_attrs)
+{
+  tree type = *node;
+
+  /* Only allow on class types (struct, class, union) */
+  if (TREE_CODE (type) != RECORD_TYPE
+      && TREE_CODE (type) != UNION_TYPE)
+    {
+      warning (OPT_Wattributes,
+	       "%qE attribute ignored on non-class type", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* For complete types, perform full validation.
+     For incomplete types, just allow the attribute - validation will
+     happen when the type is used or becomes complete.  */
+  if (COMPLETE_TYPE_P (type))
+    {
+      /* Check for virtual bases.  */
+      if (TYPE_BINFO (type) && BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) > 0)
+	{
+	  for (unsigned int i = 0;
+	       i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); ++i)
+	    {
+	      tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
+	      if (BINFO_VIRTUAL_P (base_binfo))
+		{
+		  warning (OPT_Wattributes,
+			  "%qE attribute ignored on type with virtual "
+			  "base classes", name);
+		  *no_add_attrs = true;
+		  return NULL_TREE;
+		}
+	    }
+	}
+
+      /* Check for virtual methods.  */
+      if (TYPE_POLYMORPHIC_P (type))
+	{
+	  warning (OPT_Wattributes,
+		  "%qE attribute ignored on type with virtual methods", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+
+      /* Check for non-trivial base classes.  */
+      if (TYPE_BINFO (type) && BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) > 0)
+	{
+	  for (unsigned int i = 0;
+	       i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); ++i)
+	    {
+	      tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
+	      tree base_type = BINFO_TYPE (base_binfo);
+
+	      if (!trivial_for_calls_p (base_type))
+		{
+		  warning (OPT_Wattributes,
+			  "%qE attribute ignored on type with non-trivial base"
+			  " class %qT", name, base_type);
+		  *no_add_attrs = true;
+		  return NULL_TREE;
+		}
+	    }
+	}
+
+      /* Check for non-trivial member types.  */
+      for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	{
+	  if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field))
+	    {
+	      tree field_type = TREE_TYPE (field);
+
+	      /* Handle array types.  */
+	      while (TREE_CODE (field_type) == ARRAY_TYPE)
+		field_type = TREE_TYPE (field_type);
+
+	      if (CLASS_TYPE_P (field_type)
+		  && !trivial_for_calls_p (field_type))
+		{
+		  warning (OPT_Wattributes, "%qE attribute ignored"
+			  " on type with non-trivial member"
+			  " %qD of type %qT", name, field, field_type);
+		  *no_add_attrs = true;
+		  return NULL_TREE;
+		}
+	    }
+	}
+
+      /* Check that not all copy/move constructors are deleted.  */
+      bool has_non_deleted_copy_or_move = false;
+
+      /* Check for non-deleted copy constructor.  */
+      if (TYPE_HAS_COPY_CTOR (type) && !TYPE_HAS_COMPLEX_COPY_CTOR (type))
+	has_non_deleted_copy_or_move = true;
+
+      /* Check for non-deleted move constructor.  */
+      if (classtype_has_non_deleted_move_ctor (type))
+	has_non_deleted_copy_or_move = true;
+
+      /* Check declared constructors.  */
+      if (CLASSTYPE_CONSTRUCTORS (type))
+	{
+	  for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (type)); iter; ++iter)
+	    {
+	      tree fn = *iter;
+	      if ((copy_fn_p (fn) || move_fn_p (fn)) && !DECL_DELETED_FN (fn))
+		{
+		  has_non_deleted_copy_or_move = true;
+		  break;
+		}
+	    }
+	}
+
+      if (!has_non_deleted_copy_or_move)
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored when all copy and"
+		  " move constructors are deleted", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  if (CLASS_TYPE_P (type) && LANG_TYPE_CLASS_CHECK (type))
+    CLASSTYPE_HAS_TRIVIAL_ABI (type) = 1;
+
+  return NULL_TREE;
+}
+
 /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
    thing pointed to by the constant.  */
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi1.C b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi1.C
new file mode 100644
index 00000000000..bd2cb81ba2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi1.C
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++11 } }
+// Test basic functionality of [[gnu::trivial_abi]] attribute
+
+struct [[gnu::trivial_abi]] TrivialAbi1 {
+    int x;
+    ~TrivialAbi1() { }  // Non-trivial destructor, but should be allowed with trivial_abi
+};
+
+class [[gnu::trivial_abi]] TrivialAbi2 {
+    int y;
+public:
+    TrivialAbi2(const TrivialAbi2&) { }  // Non-trivial copy constructor, but should be allowed
+    ~TrivialAbi2() { }
+};
+
+// Test that the attribute is recognized and stored
+static_assert(__builtin_is_trivially_relocatable(TrivialAbi1), "TrivialAbi1 should be trivially relocatable");
+static_assert(__builtin_is_trivially_relocatable(TrivialAbi2), "TrivialAbi2 should be trivially relocatable");
+
+// Test basic usage in function parameters and return values
+TrivialAbi1 func1(TrivialAbi1 param) {
+    return param;
+}
+
+TrivialAbi2 func2(TrivialAbi2 param) {
+    return param;
+}
+
+union [[gnu::trivial_abi]] TrivialUnion {
+    int a;
+    float b;
+    ~TrivialUnion() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(TrivialUnion), "TrivialUnion should be trivially relocatable");
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi2.C b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi2.C
new file mode 100644
index 00000000000..0961d502d91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi2.C
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++11 } }
+// Test error cases and restrictions for [[gnu::trivial_abi]] attribute
+
+// Test: attribute rejected on non-class types
+int [[gnu::trivial_abi]] x;  // { dg-warning "attribute ignored" }
+typedef int [[gnu::trivial_abi]] int_t;  // { dg-warning "attribute ignored" }
+
+// Test: attribute rejected on types with virtual functions
+struct [[gnu::trivial_abi]] WithVirtual {  // { dg-warning "attribute ignored on type with virtual methods" }
+    virtual void f() { }
+};
+
+// Test: attribute rejected on types with virtual bases
+struct Base { };
+struct [[gnu::trivial_abi]] WithVirtualBase : virtual Base {  // { dg-warning "attribute ignored on type with virtual base classes" }
+    int x;
+};
+
+// Test: attribute rejected when all copy/move constructors are deleted
+struct [[gnu::trivial_abi]] AllDeleted {  // { dg-warning "attribute ignored when all copy and move constructors are deleted" }
+    AllDeleted(const AllDeleted&) = delete;
+    AllDeleted(AllDeleted&&) = delete;
+    int x;
+};
+
+// Test: attribute rejected on types with non-trivial base classes
+struct NonTrivialBase {
+    NonTrivialBase(const NonTrivialBase&) { }  // Non-trivial copy
+};
+
+struct [[gnu::trivial_abi]] WithNonTrivialBase : NonTrivialBase {  // { dg-warning "attribute ignored on type with non-trivial base class" }
+    int x;
+};
+
+// Test: attribute rejected on types with non-trivial member types
+struct NonTrivialMember {
+    NonTrivialMember(const NonTrivialMember&) { }  // Non-trivial copy
+};
+
+struct [[gnu::trivial_abi]] WithNonTrivialMember {  // { dg-warning "attribute ignored on type with non-trivial member.*of type.*NonTrivialMember" }
+    NonTrivialMember member;
+    int x;
+};
+
+// Test: attribute rejected on array members of non-trivial types
+struct [[gnu::trivial_abi]] WithNonTrivialArray {  // { dg-warning "attribute ignored on type with non-trivial member.*of type.*NonTrivialMember" }
+    NonTrivialMember arr[5];
+    int x;
+};
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi3.C b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi3.C
new file mode 100644
index 00000000000..6324c7abb8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi3.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+// Test ABI behavior of [[gnu::trivial_abi]] attribute
+// This test verifies that types with trivial_abi are passed by value
+// instead of by invisible reference, even with non-trivial constructors
+
+struct [[gnu::trivial_abi]] TrivialAbiType {
+    int data;
+    TrivialAbiType() : data(0) { }
+    TrivialAbiType(const TrivialAbiType& other) : data(other.data) { }
+    TrivialAbiType(TrivialAbiType&& other) : data(other.data) { }
+    ~TrivialAbiType() { }
+};
+
+struct NonTrivialType {
+    int data;
+    NonTrivialType() : data(0) { }
+    NonTrivialType(const NonTrivialType& other) : data(other.data) { }
+    NonTrivialType(NonTrivialType&& other) : data(other.data) { }
+    ~NonTrivialType() { }
+};
+
+// Test that trivial_abi types are considered trivially relocatable
+static_assert(__builtin_is_trivially_relocatable(TrivialAbiType),
+              "TrivialAbiType should be trivially relocatable");
+static_assert(!__builtin_is_trivially_relocatable(NonTrivialType),
+              "NonTrivialType should not be trivially relocatable");
+
+// Function templates to test parameter passing
+template<typename T>
+void test_param_passing(T param) {
+    // Function body doesn't matter for ABI test
+}
+
+// Test usage
+void test_functions() {
+    TrivialAbiType trivial_obj;
+    NonTrivialType non_trivial_obj;
+
+    // Both should compile, but with different ABI behavior
+    test_param_passing(trivial_obj);     // Should pass by value
+    test_param_passing(non_trivial_obj); // Should pass by invisible reference
+}
+
+// Test return values
+TrivialAbiType return_trivial() {
+    return TrivialAbiType{};
+}
+
+NonTrivialType return_non_trivial() {
+    return NonTrivialType{};
+}
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi4.C b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi4.C
new file mode 100644
index 00000000000..2e8de94570b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi4.C
@@ -0,0 +1,69 @@
+// { dg-do compile { target c++11 } }
+// Test edge cases and inheritance with [[gnu::trivial_abi]] attribute
+
+// Test: Derived classes with trivial_abi base classes
+struct [[gnu::trivial_abi]] TrivialBase {
+    int x;
+    ~TrivialBase() { }
+};
+
+// This should be allowed - base class has trivial_abi
+struct [[gnu::trivial_abi]] DerivedFromTrivial : TrivialBase {
+    int y;
+    ~DerivedFromTrivial() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(TrivialBase),
+              "TrivialBase should be trivially relocatable");
+static_assert(__builtin_is_trivially_relocatable(DerivedFromTrivial),
+              "DerivedFromTrivial should be trivially relocatable");
+
+// Test: Multiple inheritance with all trivial bases
+struct [[gnu::trivial_abi]] TrivialBase2 {
+    int z;
+    ~TrivialBase2() { }
+};
+
+struct [[gnu::trivial_abi]] MultipleInheritance : TrivialBase, TrivialBase2 {
+    int w;
+    ~MultipleInheritance() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(MultipleInheritance),
+              "MultipleInheritance should be trivially relocatable");
+
+// Test: Empty class with trivial_abi
+struct [[gnu::trivial_abi]] EmptyTrivialAbi {
+    ~EmptyTrivialAbi() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(EmptyTrivialAbi),
+              "EmptyTrivialAbi should be trivially relocatable");
+
+// Test: Class with only trivial members
+struct [[gnu::trivial_abi]] OnlyTrivialMembers {
+    int a;
+    float b;
+    char c[10];
+    ~OnlyTrivialMembers() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(OnlyTrivialMembers),
+              "OnlyTrivialMembers should be trivially relocatable");
+
+// Test: Template class with trivial_abi
+template<typename T>
+struct [[gnu::trivial_abi]] TemplateTrivialAbi {
+    T data;
+    ~TemplateTrivialAbi() { }
+};
+
+// This should work for scalar types
+using IntTrivialAbi = TemplateTrivialAbi<int>;
+static_assert(__builtin_is_trivially_relocatable(IntTrivialAbi),
+              "IntTrivialAbi should be trivially relocatable");
+
+// Test with another trivial_abi type as template parameter
+using NestedTrivialAbi = TemplateTrivialAbi<TrivialBase>;
+static_assert(__builtin_is_trivially_relocatable(NestedTrivialAbi),
+              "NestedTrivialAbi should be trivially relocatable");
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi5.C b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi5.C
new file mode 100644
index 00000000000..696d20fa696
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi5.C
@@ -0,0 +1,72 @@
+// { dg-do compile { target c++11 } }
+// Test compatibility of [[gnu::trivial_abi]] with other GCC features
+
+// Test: Compatibility with other attributes
+struct [[gnu::trivial_abi, gnu::packed]] TrivialAbiPacked {
+    char a;
+    int b;
+    ~TrivialAbiPacked() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(TrivialAbiPacked),
+              "TrivialAbiPacked should be trivially relocatable");
+
+// Test: Compatibility with alignas
+struct [[gnu::trivial_abi]] alignas(16) TrivialAbiAligned {
+    int x;
+    ~TrivialAbiAligned() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(TrivialAbiAligned),
+              "TrivialAbiAligned should be trivially relocatable");
+
+// Test: Forward declaration and later definition
+struct TrivialForward;
+struct [[gnu::trivial_abi]] TrivialForward {
+    int x;
+    ~TrivialForward() { }
+};
+
+static_assert(__builtin_is_trivially_relocatable(TrivialForward),
+              "TrivialForward should be trivially relocatable");
+
+// Test: typedef and using declarations
+using TrivialAlias = TrivialAbiPacked;
+typedef TrivialAbiAligned TrivialTypedef;
+
+static_assert(__builtin_is_trivially_relocatable(TrivialAlias),
+              "TrivialAlias should be trivially relocatable");
+static_assert(__builtin_is_trivially_relocatable(TrivialTypedef),
+              "TrivialTypedef should be trivially relocatable");
+
+// Test: Local classes
+void test_local_class() {
+    struct [[gnu::trivial_abi]] LocalTrivial {
+        int x;
+        ~LocalTrivial() { }
+    };
+
+    static_assert(__builtin_is_trivially_relocatable(LocalTrivial),
+                  "LocalTrivial should be trivially relocatable");
+}
+
+// Test: Named nested structs with trivial_abi
+struct ContainerClass {
+    struct [[gnu::trivial_abi]] NestedStruct {
+        int nested_member;
+        ~NestedStruct() { }
+    };
+};
+
+// Test: Nested classes
+struct Outer {
+    struct [[gnu::trivial_abi]] Nested {
+        int value;
+        ~Nested() { }
+    };
+};
+
+static_assert(__builtin_is_trivially_relocatable(ContainerClass::NestedStruct),
+              "ContainerClass::NestedStruct should be trivially relocatable");
+static_assert(__builtin_is_trivially_relocatable(Outer::Nested),
+              "Outer::Nested should be trivially relocatable");
\ No newline at end of file
-- 
2.51.0

Reply via email to