Fix native_type non-native_inline fields, add tests (#8655)

* Fix native_type non-native_inline fields, add tests

* Format

* Add 'native_type_test' and 'native_inline_table_test' to generate_code.py

* Remove '--gen-compare' from native_type_test generation
diff --git a/scripts/generate_code.py b/scripts/generate_code.py
index c34e0ba..500a370 100755
--- a/scripts/generate_code.py
+++ b/scripts/generate_code.py
@@ -334,6 +334,16 @@
 )
 
 flatc(
+    ["--cpp", "--gen-mutable", "--gen-object-api", "--reflect-names"],
+    schema="native_type_test.fbs",
+)
+
+flatc(
+    ["--cpp", "--gen-mutable", "--gen-compare", "--gen-object-api", "--reflect-names"],
+    schema="native_inline_table_test.fbs",
+)
+
+flatc(
     RUST_OPTS,
     prefix="arrays_test",
     schema="arrays_test.fbs",
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 833d462..1fa0665 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -3217,7 +3217,13 @@
             const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
             if (pack_name) { unpack_call += pack_name->constant; }
             unpack_call += "(*" + val + ")";
-            return unpack_call;
+            if (invector || afield.native_inline) {
+              return unpack_call;
+            } else {
+              const auto name = native_type->constant;
+              const auto ptype = GenTypeNativePtr(name, &afield, true);
+              return ptype + "(new " + name + "(" + unpack_call + "))";
+            }
           } else if (invector || afield.native_inline) {
             return "*" + val;
           } else {
@@ -3601,12 +3607,16 @@
         if (IsStruct(field.value.type)) {
           const auto &struct_attribs = field.value.type.struct_def->attributes;
           const auto native_type = struct_attribs.Lookup("native_type");
-          if (native_type) {
+          if (native_type && field.native_inline) {
             code += "::flatbuffers::Pack";
             const auto pack_name =
                 struct_attribs.Lookup("native_type_pack_name");
             if (pack_name) { code += pack_name->constant; }
             code += "(" + value + ")";
+          } else if (native_type && !field.native_inline) {
+            code += WrapInNameSpace(*field.value.type.struct_def) + "{};";
+            code += " if (_o->" + Name(field) + ") _" + Name(field) +
+                    " = ::flatbuffers::Pack(*_o->" + Name(field) + ")";
           } else if (field.native_inline) {
             code += "&" + value;
           } else {
@@ -3735,16 +3745,22 @@
         if (field->deprecated) { continue; }
 
         bool pass_by_address = false;
+        bool check_ptr = false;
         if (field->value.type.base_type == BASE_TYPE_STRUCT) {
           if (IsStruct(field->value.type)) {
             auto native_type =
                 field->value.type.struct_def->attributes.Lookup("native_type");
+            auto native_inline = field->attributes.Lookup("native_inline");
             if (native_type) { pass_by_address = true; }
+            if (native_type && !native_inline) { check_ptr = true; }
           }
         }
 
         // Call the CreateX function using values from |_o|.
-        if (pass_by_address) {
+        if (pass_by_address && check_ptr) {
+          code_ += ",\n      _o->" + Name(*field) + " ? &_" + Name(*field) +
+                   " : nullptr\\";
+        } else if (pass_by_address) {
           code_ += ",\n      &_" + Name(*field) + "\\";
         } else {
           code_ += ",\n      _" + Name(*field) + "\\";
diff --git a/tests/native_type_test.fbs b/tests/native_type_test.fbs
index e22150f..2b7d547 100644
--- a/tests/native_type_test.fbs
+++ b/tests/native_type_test.fbs
@@ -17,6 +17,8 @@
 table ApplicationData {
   vectors:[Vector3D];
   vectors_alt:[Vector3DAlt];
+  position:Vector3D;
+  position_inline:Vector3D (native_inline);
 }
 
 root_type ApplicationData;
diff --git a/tests/native_type_test_generated.h b/tests/native_type_test_generated.h
index afea063..55585f3 100644
--- a/tests/native_type_test_generated.h
+++ b/tests/native_type_test_generated.h
@@ -117,6 +117,12 @@
   typedef ApplicationData TableType;
   std::vector<Native::Vector3D> vectors{};
   std::vector<Native::Vector3D> vectors_alt{};
+  std::unique_ptr<Native::Vector3D> position{};
+  Native::Vector3D position_inline{};
+  ApplicationDataT() = default;
+  ApplicationDataT(const ApplicationDataT &o);
+  ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default;
+  ApplicationDataT &operator=(ApplicationDataT o) FLATBUFFERS_NOEXCEPT;
 };
 
 struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
@@ -127,7 +133,9 @@
   }
   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
     VT_VECTORS = 4,
-    VT_VECTORS_ALT = 6
+    VT_VECTORS_ALT = 6,
+    VT_POSITION = 8,
+    VT_POSITION_INLINE = 10
   };
   const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
     return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
@@ -141,12 +149,26 @@
   ::flatbuffers::Vector<const Geometry::Vector3DAlt *> *mutable_vectors_alt() {
     return GetPointer<::flatbuffers::Vector<const Geometry::Vector3DAlt *> *>(VT_VECTORS_ALT);
   }
+  const Geometry::Vector3D *position() const {
+    return GetStruct<const Geometry::Vector3D *>(VT_POSITION);
+  }
+  Geometry::Vector3D *mutable_position() {
+    return GetStruct<Geometry::Vector3D *>(VT_POSITION);
+  }
+  const Geometry::Vector3D *position_inline() const {
+    return GetStruct<const Geometry::Vector3D *>(VT_POSITION_INLINE);
+  }
+  Geometry::Vector3D *mutable_position_inline() {
+    return GetStruct<Geometry::Vector3D *>(VT_POSITION_INLINE);
+  }
   bool Verify(::flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyOffset(verifier, VT_VECTORS) &&
            verifier.VerifyVector(vectors()) &&
            VerifyOffset(verifier, VT_VECTORS_ALT) &&
            verifier.VerifyVector(vectors_alt()) &&
+           VerifyField<Geometry::Vector3D>(verifier, VT_POSITION, 4) &&
+           VerifyField<Geometry::Vector3D>(verifier, VT_POSITION_INLINE, 4) &&
            verifier.EndTable();
   }
   ApplicationDataT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -164,6 +186,12 @@
   void add_vectors_alt(::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3DAlt *>> vectors_alt) {
     fbb_.AddOffset(ApplicationData::VT_VECTORS_ALT, vectors_alt);
   }
+  void add_position(const Geometry::Vector3D *position) {
+    fbb_.AddStruct(ApplicationData::VT_POSITION, position);
+  }
+  void add_position_inline(const Geometry::Vector3D *position_inline) {
+    fbb_.AddStruct(ApplicationData::VT_POSITION_INLINE, position_inline);
+  }
   explicit ApplicationDataBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
@@ -178,8 +206,12 @@
 inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(
     ::flatbuffers::FlatBufferBuilder &_fbb,
     ::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3D *>> vectors = 0,
-    ::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3DAlt *>> vectors_alt = 0) {
+    ::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3DAlt *>> vectors_alt = 0,
+    const Geometry::Vector3D *position = nullptr,
+    const Geometry::Vector3D *position_inline = nullptr) {
   ApplicationDataBuilder builder_(_fbb);
+  builder_.add_position_inline(position_inline);
+  builder_.add_position(position);
   builder_.add_vectors_alt(vectors_alt);
   builder_.add_vectors(vectors);
   return builder_.Finish();
@@ -188,17 +220,36 @@
 inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
     ::flatbuffers::FlatBufferBuilder &_fbb,
     const std::vector<Geometry::Vector3D> *vectors = nullptr,
-    const std::vector<Geometry::Vector3DAlt> *vectors_alt = nullptr) {
+    const std::vector<Geometry::Vector3DAlt> *vectors_alt = nullptr,
+    const Geometry::Vector3D *position = nullptr,
+    const Geometry::Vector3D *position_inline = nullptr) {
   auto vectors__ = vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3D>(*vectors) : 0;
   auto vectors_alt__ = vectors_alt ? _fbb.CreateVectorOfStructs<Geometry::Vector3DAlt>(*vectors_alt) : 0;
   return Geometry::CreateApplicationData(
       _fbb,
       vectors__,
-      vectors_alt__);
+      vectors_alt__,
+      position,
+      position_inline);
 }
 
 ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
 
+inline ApplicationDataT::ApplicationDataT(const ApplicationDataT &o)
+      : vectors(o.vectors),
+        vectors_alt(o.vectors_alt),
+        position((o.position) ? new Native::Vector3D(*o.position) : nullptr),
+        position_inline(o.position_inline) {
+}
+
+inline ApplicationDataT &ApplicationDataT::operator=(ApplicationDataT o) FLATBUFFERS_NOEXCEPT {
+  std::swap(vectors, o.vectors);
+  std::swap(vectors_alt, o.vectors_alt);
+  std::swap(position, o.position);
+  std::swap(position_inline, o.position_inline);
+  return *this;
+}
+
 inline ApplicationDataT *ApplicationData::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
   auto _o = std::unique_ptr<ApplicationDataT>(new ApplicationDataT());
   UnPackTo(_o.get(), _resolver);
@@ -210,6 +261,8 @@
   (void)_resolver;
   { auto _e = vectors(); if (_e) { _o->vectors.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vectors[_i] = ::flatbuffers::UnPack(*_e->Get(_i)); } } else { _o->vectors.resize(0); } }
   { auto _e = vectors_alt(); if (_e) { _o->vectors_alt.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vectors_alt[_i] = ::flatbuffers::UnPackVector3DAlt(*_e->Get(_i)); } } else { _o->vectors_alt.resize(0); } }
+  { auto _e = position(); if (_e) _o->position = std::unique_ptr<Native::Vector3D>(new Native::Vector3D(::flatbuffers::UnPack(*_e))); }
+  { auto _e = position_inline(); if (_e) _o->position_inline = ::flatbuffers::UnPack(*_e); }
 }
 
 inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@@ -222,10 +275,14 @@
   struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const ApplicationDataT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   auto _vectors = _o->vectors.size() ? _fbb.CreateVectorOfNativeStructs<Geometry::Vector3D, Native::Vector3D>(_o->vectors) : 0;
   auto _vectors_alt = _o->vectors_alt.size() ? _fbb.CreateVectorOfNativeStructs<Geometry::Vector3DAlt, Native::Vector3D>(_o->vectors_alt, ::flatbuffers::PackVector3DAlt) : 0;
+  auto _position = Geometry::Vector3D{}; if (_o->position) _position = ::flatbuffers::Pack(*_o->position);
+  auto _position_inline = ::flatbuffers::Pack(_o->position_inline);
   return Geometry::CreateApplicationData(
       _fbb,
       _vectors,
-      _vectors_alt);
+      _vectors_alt,
+      _o->position ? &_position : nullptr,
+      &_position_inline);
 }
 
 inline const ::flatbuffers::TypeTable *Vector3DTypeTable() {
@@ -267,7 +324,9 @@
 inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
   static const ::flatbuffers::TypeCode type_codes[] = {
     { ::flatbuffers::ET_SEQUENCE, 1, 0 },
-    { ::flatbuffers::ET_SEQUENCE, 1, 1 }
+    { ::flatbuffers::ET_SEQUENCE, 1, 1 },
+    { ::flatbuffers::ET_SEQUENCE, 0, 0 },
+    { ::flatbuffers::ET_SEQUENCE, 0, 0 }
   };
   static const ::flatbuffers::TypeFunction type_refs[] = {
     Geometry::Vector3DTypeTable,
@@ -275,10 +334,12 @@
   };
   static const char * const names[] = {
     "vectors",
-    "vectors_alt"
+    "vectors_alt",
+    "position",
+    "position_inline"
   };
   static const ::flatbuffers::TypeTable tt = {
-    ::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, names
+    ::flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, nullptr, names
   };
   return &tt;
 }
diff --git a/tests/test.cpp b/tests/test.cpp
index a374da5..1564fa7 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -909,6 +909,9 @@
   const int N = 3;
 
   Geometry::ApplicationDataT src_data;
+  src_data.position = flatbuffers::unique_ptr<Native::Vector3D>(
+      new Native::Vector3D(1.0f, 2.0f, 3.0f));
+  src_data.position_inline = Native::Vector3D(4.0f, 5.0f, 6.0f);
   src_data.vectors.reserve(N);
   src_data.vectors_alt.reserve(N);
 
@@ -924,6 +927,13 @@
 
   auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
 
+  TEST_EQ(dstDataT->position->x, 1.0f);
+  TEST_EQ(dstDataT->position->y, 2.0f);
+  TEST_EQ(dstDataT->position->z, 3.0f);
+  TEST_EQ(dstDataT->position_inline.x, 4.0f);
+  TEST_EQ(dstDataT->position_inline.y, 5.0f);
+  TEST_EQ(dstDataT->position_inline.z, 6.0f);
+
   for (int i = 0; i < N; ++i) {
     const Native::Vector3D &v = dstDataT->vectors[i];
     TEST_EQ(v.x, 10 * i + 0.1f);