Really bad support for struct types as types (in member variables, parameters, etc.) :)

This is necessary in order to support member functions (including special member functions), so that their `this` parameter can be represented.

PiperOrigin-RevId: 402912882
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index f88f28c..03618a8 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -72,6 +72,26 @@
       success = false;
       continue;
     }
+
+    if (const clang::RecordType* record_type =
+            llvm::dyn_cast<clang::RecordType>(param->getType())) {
+      if (clang::RecordDecl* record_decl =
+              llvm::dyn_cast<clang::RecordDecl>(record_type->getDecl())) {
+        // TODO(b/200067242): non-trivial_abi structs, when passed by value,
+        // have a different representation which needs special support. We
+        // currently do not support it.
+        if (!record_decl->canPassInRegisters()) {
+          ir_.items.push_back(UnsupportedItem{
+              .name = function_decl->getQualifiedNameAsString(),
+              .message = absl::Substitute("Non-trivial_abi type '$0' is not "
+                                          "supported by value as a parameter",
+                                          param->getType().getAsString()),
+              .source_loc = ConvertSourceLoc(param->getBeginLoc())});
+          success = false;
+        }
+      }
+    }
+
     std::optional<Identifier> param_name = GetTranslatedIdentifier(param);
     if (!param_name.has_value()) {
       ir_.items.push_back(UnsupportedItem{
@@ -84,6 +104,27 @@
     params.push_back({*param_type, *std::move(param_name)});
   }
 
+  if (const clang::RecordType* record_return_type =
+          llvm::dyn_cast<clang::RecordType>(function_decl->getReturnType())) {
+    if (clang::RecordDecl* record_decl =
+            llvm::dyn_cast<clang::RecordDecl>(record_return_type->getDecl())) {
+      // TODO(b/200067242): non-trivial_abi structs, when passed by value,
+      // have a different representation which needs special support. We
+      // currently do not support it.
+      if (!record_decl->canPassInRegisters()) {
+        ir_.items.push_back(UnsupportedItem{
+            .name = function_decl->getQualifiedNameAsString(),
+            .message =
+                absl::Substitute("Non-trivial_abi type '$0' is not supported "
+                                 "by value as a return type",
+                                 function_decl->getReturnType().getAsString()),
+            .source_loc =
+                ConvertSourceLoc(function_decl->getReturnTypeSourceRange())});
+        success = false;
+      }
+    }
+  }
+
   auto return_type = ConvertType(function_decl->getReturnType());
   if (!return_type.ok()) {
     ir_.items.push_back(UnsupportedItem{
@@ -267,6 +308,10 @@
                    .column = sm.getSpellingColumnNumber(loc)};
 }
 
+SourceLoc AstVisitor::ConvertSourceLoc(clang::SourceRange range) const {
+  return ConvertSourceLoc(range.getBegin());
+}
+
 absl::StatusOr<MappedType> AstVisitor::ConvertType(
     clang::QualType qual_type) const {
   std::optional<MappedType> type = std::nullopt;
@@ -310,6 +355,15 @@
           }
         }
     }
+  } else if (const clang::TagType* tag_type =
+                 qual_type->getAs<clang::TagType>()) {
+    // TODO(b/202692734): If tag_type is un-importable, fail here.
+    clang::TagDecl* tag_decl = tag_type->getDecl();
+
+    if (std::optional<Identifier> id = GetTranslatedIdentifier(tag_decl)) {
+      std::string ident(id->Ident());
+      return MappedType::Simple(ident, ident);
+    }
   }
 
   if (!type.has_value()) {
diff --git a/rs_bindings_from_cc/ast_visitor.h b/rs_bindings_from_cc/ast_visitor.h
index 2c7bf1c..c19b4c4 100644
--- a/rs_bindings_from_cc/ast_visitor.h
+++ b/rs_bindings_from_cc/ast_visitor.h
@@ -74,6 +74,7 @@
   // Gets the doc comment of the declaration.
   std::optional<std::string> GetComment(const clang::Decl* decl) const;
   SourceLoc ConvertSourceLoc(clang::SourceLocation loc) const;
+  SourceLoc ConvertSourceLoc(clang::SourceRange range) const;
   absl::StatusOr<MappedType> ConvertType(clang::QualType qual_type) const;
 
   absl::Span<const absl::string_view> public_header_names_;
diff --git a/rs_bindings_from_cc/ast_visitor_test.cc b/rs_bindings_from_cc/ast_visitor_test.cc
index 67108af..7784057 100644
--- a/rs_bindings_from_cc/ast_visitor_test.cc
+++ b/rs_bindings_from_cc/ast_visitor_test.cc
@@ -301,9 +301,12 @@
 }
 
 TEST(AstVisitorTest, TrivialCopyConstructor) {
-  absl::string_view file =
-      "struct Implicit {};\n"
-      "struct Defaulted { Defaulted(const Defaulted&) = default; };\n";
+  absl::string_view file = R"cc(
+    struct Implicit {};
+    struct Defaulted {
+      Defaulted(const Defaulted&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -313,36 +316,55 @@
 }
 
 TEST(AstVisitorTest, NontrivialCopyConstructor) {
-  absl::string_view file = "struct Defined { Defined(const Defined&);};\n";
-  // TODO(b/202113881): "struct MemberImplicit { Defined x; };\n"
-  // TODO(b/202113881): "struct MemberDefaulted { MemberDefaulted(const
-  // MemberDefaulted&) = default; Defined x; };\n"
+  absl::string_view file = R"cc(
+    struct Defined {
+      Defined(const Defined&);
+    };
+    struct MemberImplicit {
+      Defined x;
+    };
+    struct MemberDefaulted {
+      MemberDefaulted(const MemberDefaulted&) = default;
+      Defined x;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
-
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(1));
+  EXPECT_THAT(records, SizeIs(3));
   EXPECT_THAT(records, Each(Pointee(CopyConstructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kNontrivial)))));
 }
 
 TEST(AstVisitorTest, DeletedCopyConstructor) {
-  absl::string_view file =
-      "struct Deleted { Deleted(const Deleted&) = delete;};\n"
-      // TODO(b/202113881): "struct DeletedByMember { Deleted x; };\n"
-      "struct DeletedByCtorDef { DeletedByCtorDef(DeletedByCtorDef&&) {} };\n";
+  absl::string_view file = R"cc(
+    struct Deleted {
+      Deleted(const Deleted&) = delete;
+    };
+    struct DeletedByMember {
+      Deleted x;
+    };
+    struct DeletedByCtorDef {
+      DeletedByCtorDef(DeletedByCtorDef&&) {}
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
-
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(2));
+  EXPECT_THAT(records, SizeIs(3));
   EXPECT_THAT(records, Each(Pointee(CopyConstructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kDeleted)))));
 }
 
 TEST(AstVisitorTest, PublicCopyConstructor) {
-  absl::string_view file =
-      "class Implicit {};\n"
-      "struct Defaulted { Defaulted(const Defaulted&) = default; };\n"
-      "class Section { public: Section(const Section&) = default; };\n";
+  absl::string_view file = R"cc(
+    class Implicit {};
+    struct Defaulted {
+      Defaulted(const Defaulted&) = default;
+    };
+    class Section {
+     public:
+      Section(const Section&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -351,9 +373,15 @@
 }
 
 TEST(AstVisitorTest, PrivateCopyConstructor) {
-  absl::string_view file =
-      "class Defaulted { Defaulted(const Defaulted&) = default; };\n"
-      "struct Section { private: Section(const Section&) = default; };\n";
+  absl::string_view file = R"cc(
+    class Defaulted {
+      Defaulted(const Defaulted&) = default;
+    };
+    struct Section {
+     private:
+      Section(const Section&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -362,9 +390,12 @@
 }
 
 TEST(AstVisitorTest, TrivialMoveConstructor) {
-  absl::string_view file =
-      "struct Implicit {};\n"
-      "struct Defaulted { Defaulted(Defaulted&&) = default; };\n";
+  absl::string_view file = R"cc(
+    struct Implicit {};
+    struct Defaulted {
+      Defaulted(Defaulted&&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -374,37 +405,55 @@
 }
 
 TEST(AstVisitorTest, NontrivialMoveConstructor) {
-  absl::string_view file = "struct Defined { Defined(Defined&&);};\n";
-  // TODO(b/202113881): "struct MemberImplicit { Defined x; };\n"
-  // TODO(b/202113881): "struct MemberDefaulted { MemberDefaulted(
-  // MemberDefaulted&&) = default; Defined x; };\n"
+  absl::string_view file = R"cc(
+    struct Defined {
+      Defined(Defined&&);
+    };
+    struct MemberImplicit {
+      Defined x;
+    };
+    struct MemberDefaulted {
+      MemberDefaulted(MemberDefaulted&&) = default;
+      Defined x;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
-
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(1));
+  EXPECT_THAT(records, SizeIs(3));
   EXPECT_THAT(records, Each(Pointee(MoveConstructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kNontrivial)))));
 }
 
 TEST(AstVisitorTest, DeletedMoveConstructor) {
-  absl::string_view file =
-      "struct Deleted { Deleted(Deleted&&) = delete;};\n"
-      // TODO(b/202113881): "struct DeletedByMember { Deleted x; };\n"
-      "struct SuppressedByCtorDef {"
-      " SuppressedByCtorDef(const SuppressedByCtorDef&) {}};\n";
+  absl::string_view file = R"cc(
+    struct Deleted {
+      Deleted(Deleted&&) = delete;
+    };
+    struct DeletedByMember {
+      Deleted x;
+    };
+    struct SuppressedByCtorDef {
+      SuppressedByCtorDef(const SuppressedByCtorDef&) {}
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
-
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(2));
+  EXPECT_THAT(records, SizeIs(3));
   EXPECT_THAT(records, Each(Pointee(MoveConstructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kDeleted)))));
 }
 
 TEST(AstVisitorTest, PublicMoveConstructor) {
-  absl::string_view file =
-      "class Implicit {};\n"
-      "struct Defaulted { Defaulted(Defaulted&&) = default; };\n"
-      "class Section { public: Section(Section&&) = default; };\n";
+  absl::string_view file = R"cc(
+    class Implicit {};
+    struct Defaulted {
+      Defaulted(Defaulted&&) = default;
+    };
+    class Section {
+     public:
+      Section(Section&&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -413,9 +462,15 @@
 }
 
 TEST(AstVisitorTest, PrivateMoveConstructor) {
-  absl::string_view file =
-      "class Defaulted { Defaulted(Defaulted&&) = default; };\n"
-      "struct Section { private: Section(Section&&) = default; };\n";
+  absl::string_view file = R"cc(
+    class Defaulted {
+      Defaulted(Defaulted&&) = default;
+    };
+    struct Section {
+     private:
+      Section(Section&&) = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -424,9 +479,12 @@
 }
 
 TEST(AstVisitorTest, TrivialDestructor) {
-  absl::string_view file =
-      "struct Implicit {};\n"
-      "struct Defaulted { ~Defaulted() = default; };\n";
+  absl::string_view file = R"cc(
+    struct Implicit {};
+    struct Defaulted {
+      ~Defaulted() = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -436,34 +494,54 @@
 }
 
 TEST(AstVisitorTest, NontrivialDestructor) {
-  absl::string_view file = "struct Defined { ~Defined();};\n";
-  // TODO(b/202113881): "struct MemberImplicit { Defined x; };\n"
-  // TODO(b/202113881): "struct MemberDefaulted { ~MemberDefaulted() = default;
-  // Defined x; };\n"
+  absl::string_view file = R"cc(
+    struct Defined {
+      ~Defined();
+    };
+    struct MemberImplicit {
+      Defined x;
+    };
+    struct MemberDefaulted {
+      ~MemberDefaulted() = default;
+      Defined x;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(1));
+  EXPECT_THAT(records, SizeIs(3));
   EXPECT_THAT(records, Each(Pointee(Destructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kNontrivial)))));
 }
 
 TEST(AstVisitorTest, DeletedDestructor) {
-  absl::string_view file = "struct Deleted { ~Deleted() = delete;};\n";
-  // TODO(b/202113881): "struct DeletedByMember { Deleted x; };\n"
+  absl::string_view file = R"cc(
+    struct Deleted {
+      ~Deleted() = delete;
+    };
+    struct DeletedByMember {
+      Deleted x;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
-  EXPECT_THAT(records, SizeIs(1));
+  EXPECT_THAT(records, SizeIs(2));
   EXPECT_THAT(records, Each(Pointee(Destructor(DefinitionIs(
                            SpecialMemberFunc::Definition::kDeleted)))));
 }
 
 TEST(AstVisitorTest, PublicDestructor) {
-  absl::string_view file =
-      "class Implicit {};\n"
-      "struct Defaulted { ~Defaulted() = default; };\n"
-      "class Section { public: ~Section() = default; };\n";
+  absl::string_view file = R"cc(
+    class Implicit {};
+    struct Defaulted {
+      ~Defaulted() = default;
+    };
+    class Section {
+     public:
+      ~Section() = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
@@ -472,9 +550,15 @@
 }
 
 TEST(AstVisitorTest, PrivateDestructor) {
-  absl::string_view file =
-      "class Defaulted { ~Defaulted() = default; };\n"
-      "struct Section { private: ~Section() = default; };\n";
+  absl::string_view file = R"cc(
+    class Defaulted {
+      ~Defaulted() = default;
+    };
+    struct Section {
+     private:
+      ~Section() = default;
+    };
+  )cc";
   ASSERT_OK_AND_ASSIGN(IR ir, IrFromCc({file}));
 
   std::vector<Record*> records = ir.get_items_if<Record>();
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type.h b/rs_bindings_from_cc/test/golden/nontrivial_type.h
index 9ce57f1..75f5f50 100644
--- a/rs_bindings_from_cc/test/golden/nontrivial_type.h
+++ b/rs_bindings_from_cc/test/golden/nontrivial_type.h
@@ -12,4 +12,6 @@
   int field;
 };
 
+void TakesByValue(Nontrivial nontrivial);
+
 #endif  // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_NONTRIVIAL_TYPE_H_
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
index f1c94be..7ec96b2 100644
--- a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
@@ -18,6 +18,10 @@
 // Error while generating bindings for item 'Nontrivial::Nontrivial':
 // Parameter type 'struct Nontrivial &&' is not supported
 
+// rs_bindings_from_cc/test/golden/nontrivial_type.h;l=11
+// Error while generating bindings for item 'TakesByValue':
+// Non-trivial_abi type 'struct Nontrivial' is not supported by value as a parameter
+
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_NONTRIVIAL_TYPE_H_
 
 mod detail {
diff --git a/rs_bindings_from_cc/test/golden/types.h b/rs_bindings_from_cc/test/golden/types.h
index ee4f14b..784c51d 100644
--- a/rs_bindings_from_cc/test/golden/types.h
+++ b/rs_bindings_from_cc/test/golden/types.h
@@ -8,6 +8,10 @@
 #include <cstddef>
 #include <cstdint>
 
+struct SomeStruct {
+  bool not_empty;  // TODO(b/202737338): delete this.
+};
+
 struct FieldTypeTestStruct {
   bool bool_field;
   char char_field;
@@ -50,6 +54,11 @@
 
   float float_field;
   double double_field;
+
+  int* ptr_field;
+
+  SomeStruct struct_field;
+  SomeStruct* struct_ptr_field;
 };
 
 inline void VoidReturningFunction() {}
diff --git a/rs_bindings_from_cc/test/golden/types_rs_api.rs b/rs_bindings_from_cc/test/golden/types_rs_api.rs
index 859d280..5d9949f 100644
--- a/rs_bindings_from_cc/test/golden/types_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/types_rs_api.rs
@@ -9,6 +9,13 @@
 
 #[derive(Clone, Copy)]
 #[repr(C)]
+pub struct SomeStruct {
+    /// TODO(b/202737338): delete this.
+    pub not_empty: bool,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
 pub struct FieldTypeTestStruct {
     pub bool_field: bool,
     pub char_field: u8,
@@ -43,6 +50,9 @@
     pub uintptr_t_field: usize,
     pub float_field: f32,
     pub double_field: f64,
+    pub ptr_field: *mut i32,
+    pub struct_field: SomeStruct,
+    pub struct_ptr_field: *mut SomeStruct,
 }
 
 #[inline(always)]
@@ -58,7 +68,11 @@
     }
 }
 
-const_assert_eq!(std::mem::size_of::<FieldTypeTestStruct>(), 168usize);
+const_assert_eq!(std::mem::size_of::<SomeStruct>(), 1usize);
+const_assert_eq!(std::mem::align_of::<SomeStruct>(), 1usize);
+const_assert_eq!(offset_of!(SomeStruct, not_empty) * 8, 0usize);
+
+const_assert_eq!(std::mem::size_of::<FieldTypeTestStruct>(), 192usize);
 const_assert_eq!(std::mem::align_of::<FieldTypeTestStruct>(), 8usize);
 const_assert_eq!(offset_of!(FieldTypeTestStruct, bool_field) * 8, 0usize);
 const_assert_eq!(offset_of!(FieldTypeTestStruct, char_field) * 8, 8usize);
@@ -93,3 +107,6 @@
 const_assert_eq!(offset_of!(FieldTypeTestStruct, uintptr_t_field) * 8, 1152usize);
 const_assert_eq!(offset_of!(FieldTypeTestStruct, float_field) * 8, 1216usize);
 const_assert_eq!(offset_of!(FieldTypeTestStruct, double_field) * 8, 1280usize);
+const_assert_eq!(offset_of!(FieldTypeTestStruct, ptr_field) * 8, 1344usize);
+const_assert_eq!(offset_of!(FieldTypeTestStruct, struct_field) * 8, 1408usize);
+const_assert_eq!(offset_of!(FieldTypeTestStruct, struct_ptr_field) * 8, 1472usize);
diff --git a/rs_bindings_from_cc/test/golden/types_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/types_rs_api_impl.cc
index b66ef7c..07c9ec9 100644
--- a/rs_bindings_from_cc/test/golden/types_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/types_rs_api_impl.cc
@@ -9,7 +9,11 @@
   return VoidReturningFunction();
 }
 
-static_assert(sizeof(FieldTypeTestStruct) == 168);
+static_assert(sizeof(SomeStruct) == 1);
+static_assert(alignof(SomeStruct) == 1);
+static_assert(offsetof(SomeStruct, not_empty) * 8 == 0);
+
+static_assert(sizeof(FieldTypeTestStruct) == 192);
 static_assert(alignof(FieldTypeTestStruct) == 8);
 static_assert(offsetof(FieldTypeTestStruct, bool_field) * 8 == 0);
 static_assert(offsetof(FieldTypeTestStruct, char_field) * 8 == 8);
@@ -45,3 +49,6 @@
 static_assert(offsetof(FieldTypeTestStruct, uintptr_t_field) * 8 == 1152);
 static_assert(offsetof(FieldTypeTestStruct, float_field) * 8 == 1216);
 static_assert(offsetof(FieldTypeTestStruct, double_field) * 8 == 1280);
+static_assert(offsetof(FieldTypeTestStruct, ptr_field) * 8 == 1344);
+static_assert(offsetof(FieldTypeTestStruct, struct_field) * 8 == 1408);
+static_assert(offsetof(FieldTypeTestStruct, struct_ptr_field) * 8 == 1472);
diff --git a/rs_bindings_from_cc/test/golden/unsupported.h b/rs_bindings_from_cc/test/golden/unsupported.h
index 204bff1..dc3cb11 100644
--- a/rs_bindings_from_cc/test/golden/unsupported.h
+++ b/rs_bindings_from_cc/test/golden/unsupported.h
@@ -5,14 +5,16 @@
 #ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_UNSUPPORTED_H_
 #define CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_UNSUPPORTED_H_
 
-struct CustomType {
+struct NontrivialCustomType {
+  NontrivialCustomType(NontrivialCustomType&&);
+
   int i;
 };
 
-void UnsupportedParamType(CustomType n);
+void UnsupportedParamType(NontrivialCustomType n);
 void UnsupportedUnnamedParam(int);
-CustomType UnsupportedReturnType();
+NontrivialCustomType UnsupportedReturnType();
 
-CustomType MultipleReasons(CustomType n, int);
+NontrivialCustomType MultipleReasons(NontrivialCustomType n, int);
 
 #endif  // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_UNSUPPORTED_H_
diff --git a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
index d22dd38..978800d 100644
--- a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
@@ -1,4 +1,4 @@
-#![feature(const_maybe_uninit_as_ptr, const_ptr_offset_from, const_raw_ptr_deref)]
+#![feature(const_maybe_uninit_as_ptr, const_ptr_offset_from, const_raw_ptr_deref, negative_impls)]
 // Part of the Crubit project, under the Apache License v2.0 with LLVM
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -7,38 +7,43 @@
 use memoffset_unstable_const::offset_of;
 use static_assertions::const_assert_eq;
 
-#[derive(Clone, Copy)]
 #[repr(C)]
-pub struct CustomType {
+pub struct NontrivialCustomType {
     pub i: i32,
 }
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=8
-// Error while generating bindings for item 'UnsupportedParamType':
-// Parameter type 'struct CustomType' is not supported
+impl !Unpin for NontrivialCustomType {}
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=9
+// rs_bindings_from_cc/test/golden/unsupported.h;l=5
+// Error while generating bindings for item 'NontrivialCustomType::NontrivialCustomType':
+// Parameter type 'struct NontrivialCustomType &&' is not supported
+
+// rs_bindings_from_cc/test/golden/unsupported.h;l=10
+// Error while generating bindings for item 'UnsupportedParamType':
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a parameter
+
+// rs_bindings_from_cc/test/golden/unsupported.h;l=11
 // Error while generating bindings for item 'UnsupportedUnnamedParam':
 // Empty parameter names are not supported
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=10
+// rs_bindings_from_cc/test/golden/unsupported.h;l=12
 // Error while generating bindings for item 'UnsupportedReturnType':
-// Return type 'struct CustomType' is not supported
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a return type
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=12
+// rs_bindings_from_cc/test/golden/unsupported.h;l=14
 // Error while generating bindings for item 'MultipleReasons':
-// Parameter type 'struct CustomType' is not supported
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a parameter
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=12
+// rs_bindings_from_cc/test/golden/unsupported.h;l=14
 // Error while generating bindings for item 'MultipleReasons':
 // Empty parameter names are not supported
 
-// rs_bindings_from_cc/test/golden/unsupported.h;l=12
+// rs_bindings_from_cc/test/golden/unsupported.h;l=14
 // Error while generating bindings for item 'MultipleReasons':
-// Return type 'struct CustomType' is not supported
+// Non-trivial_abi type 'struct NontrivialCustomType' is not supported by value as a return type
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_UNSUPPORTED_H_
 
-const_assert_eq!(std::mem::size_of::<CustomType>(), 4usize);
-const_assert_eq!(std::mem::align_of::<CustomType>(), 4usize);
-const_assert_eq!(offset_of!(CustomType, i) * 8, 0usize);
+const_assert_eq!(std::mem::size_of::<NontrivialCustomType>(), 4usize);
+const_assert_eq!(std::mem::align_of::<NontrivialCustomType>(), 4usize);
+const_assert_eq!(offset_of!(NontrivialCustomType, i) * 8, 0usize);
diff --git a/rs_bindings_from_cc/test/golden/unsupported_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/unsupported_rs_api_impl.cc
index 82da54d..cc9fb1a 100644
--- a/rs_bindings_from_cc/test/golden/unsupported_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/unsupported_rs_api_impl.cc
@@ -5,6 +5,6 @@
 #include <cstddef>
 #include "rs_bindings_from_cc/test/golden/unsupported.h"
 
-static_assert(sizeof(CustomType) == 4);
-static_assert(alignof(CustomType) == 4);
-static_assert(offsetof(CustomType, i) * 8 == 0);
+static_assert(sizeof(NontrivialCustomType) == 4);
+static_assert(alignof(NontrivialCustomType) == 4);
+static_assert(offsetof(NontrivialCustomType, i) * 8 == 0);