From 19aa2ce42060fb136bc08af7ad3a02156c8023d6 Mon Sep 17 00:00:00 2001 From: Romain BOULLARD Date: Sat, 9 May 2026 20:35:36 +0200 Subject: [PATCH] Fix CreateVectorOfNativeStructs for non-std vector types (cpp_vec_type + native_type) When a field combines cpp_vec_type (e.g. eastl::vector) with native_type on a struct, the generated Pack method now uses the pointer+size overload of CreateVectorOfNativeStructs instead of the std::vector overload, which only accepts std::vector. Adds a dedicated test covering the combined attribute case. Co-Authored-By: Claude Sonnet 4.6 --- CMakeLists.txt | 3 ++ src/idl_gen_cpp.cpp | 9 +++++- tests/cpp_vec_type_native_type_test.fbs | 15 +++++++++ tests/cpp_vec_type_native_type_test_impl.cpp | 15 +++++++++ tests/cpp_vec_type_native_type_test_impl.h | 34 ++++++++++++++++++++ tests/test.cpp | 33 +++++++++++++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/cpp_vec_type_native_type_test.fbs create mode 100644 tests/cpp_vec_type_native_type_test_impl.cpp create mode 100644 tests/cpp_vec_type_native_type_test_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e41a13d5b..c0d0819e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,6 +241,8 @@ set(FlatBuffers_Tests_SRCS tests/native_type_test_impl.h tests/native_type_test_impl.cpp tests/cpp_vec_type_test_impl.h + tests/cpp_vec_type_native_type_test_impl.h + tests/cpp_vec_type_native_type_test_impl.cpp tests/alignment_test.h tests/alignment_test.cpp tests/64bit/offset64_test.h @@ -556,6 +558,7 @@ if(FLATBUFFERS_BUILD_TESTS) compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/cpp_vec_type_test.fbs "${FLATC_OPT_COMP}") + compile_schema_for_test(tests/cpp_vec_type_native_type_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/key_field/key_field_sample.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/64bit/test_64bit.fbs "${FLATC_OPT_COMP};--bfbs-gen-embed") compile_schema_for_test(tests/64bit/evolution/v1.fbs "${FLATC_OPT_COMP}") diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 100564f1a..67dcbf7f6 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -3833,7 +3833,6 @@ class CppGenerator : public BaseGenerator { code += "_fbb.CreateVectorOfNativeStructs<"; code += WrapInNameSpace(*vector_type.struct_def) + ", " + native_type->constant + ">"; - code += "(" + value; // Field-level native_type_pack_name takes priority over // struct-level auto field_pack_name = @@ -3842,6 +3841,14 @@ class CppGenerator : public BaseGenerator { field_pack_name ? field_pack_name : struct_attrs.Lookup("native_type_pack_name"); + // Non-std vectors (e.g. eastl::vector) don't match the + // std::vector overload, so use the pointer+size overload. + const bool is_std_vec = NativeVector(&field) == "std::vector"; + if (is_std_vec) { + code += "(" + value; + } else { + code += "(" + value + ".data(), " + value + ".size()"; + } if (pack_name) { code += ", ::flatbuffers::Pack" + pack_name->constant; } diff --git a/tests/cpp_vec_type_native_type_test.fbs b/tests/cpp_vec_type_native_type_test.fbs new file mode 100644 index 000000000..f8918fd6c --- /dev/null +++ b/tests/cpp_vec_type_native_type_test.fbs @@ -0,0 +1,15 @@ +native_include "cpp_vec_type_native_type_test_impl.h"; + +namespace CppVecNativeTypeTest; + +struct Vec3 (native_type: "CppVecNativeTypeTest::Native::Vec3") { + x: float; + y: float; + z: float; +} + +table Container { + points: [Vec3] (cpp_vec_type: "CppVecNativeTypeTest::CustomVec"); +} + +root_type Container; diff --git a/tests/cpp_vec_type_native_type_test_impl.cpp b/tests/cpp_vec_type_native_type_test_impl.cpp new file mode 100644 index 000000000..373b9d20f --- /dev/null +++ b/tests/cpp_vec_type_native_type_test_impl.cpp @@ -0,0 +1,15 @@ +#include "cpp_vec_type_native_type_test_impl.h" + +#include "cpp_vec_type_native_type_test_generated.h" + +namespace flatbuffers { +CppVecNativeTypeTest::Vec3 Pack( + const CppVecNativeTypeTest::Native::Vec3& obj) { + return CppVecNativeTypeTest::Vec3(obj.x, obj.y, obj.z); +} + +const CppVecNativeTypeTest::Native::Vec3 UnPack( + const CppVecNativeTypeTest::Vec3& obj) { + return CppVecNativeTypeTest::Native::Vec3(obj.x(), obj.y(), obj.z()); +} +} // namespace flatbuffers diff --git a/tests/cpp_vec_type_native_type_test_impl.h b/tests/cpp_vec_type_native_type_test_impl.h new file mode 100644 index 000000000..c91995ef4 --- /dev/null +++ b/tests/cpp_vec_type_native_type_test_impl.h @@ -0,0 +1,34 @@ +#ifndef CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H +#define CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H + +#include + +namespace CppVecNativeTypeTest { + +namespace Native { +struct Vec3 { + float x, y, z; + Vec3() : x(0), y(0), z(0) {} + Vec3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {} + bool operator==(const Vec3& o) const { + return x == o.x && y == o.y && z == o.z; + } +}; +} // namespace Native + +template +struct CustomVec : public std::vector { + using std::vector::vector; +}; + +struct Vec3; // flatbuffers-generated struct + +} // namespace CppVecNativeTypeTest + +namespace flatbuffers { +CppVecNativeTypeTest::Vec3 Pack(const CppVecNativeTypeTest::Native::Vec3& obj); +const CppVecNativeTypeTest::Native::Vec3 UnPack( + const CppVecNativeTypeTest::Vec3& obj); +} // namespace flatbuffers + +#endif // CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H diff --git a/tests/test.cpp b/tests/test.cpp index 14fbe1339..34dd753ad 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -65,6 +65,7 @@ #include "monster_test_bfbs_generated.h" // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed #include "cpp_vec_type_test_generated.h" #include "native_type_test_generated.h" +#include "cpp_vec_type_native_type_test_generated.h" #include "test_assert.h" #include "util_test.h" #include "vector_table_naked_ptr_test.h" @@ -1041,6 +1042,37 @@ void CppVecTypeTest() { TEST_ASSERT(*dst == *dst); } +void CppVecTypeNativeTypeTest() { + // Verify that combining cpp_vec_type + native_type on a vector of structs + // produces the correct container type in the NativeTable. + static_assert( + std::is_same< + decltype(CppVecNativeTypeTest::ContainerT{}.points), + CppVecNativeTypeTest::CustomVec< + CppVecNativeTypeTest::Native::Vec3>>::value, + "points should be CustomVec"); + + const int N = 3; + CppVecNativeTypeTest::ContainerT src; + for (int i = 0; i < N; ++i) { + src.points.push_back( + CppVecNativeTypeTest::Native::Vec3(1.0f * i, 2.0f * i, 3.0f * i)); + } + + flatbuffers::FlatBufferBuilder fbb; + fbb.Finish(CppVecNativeTypeTest::Container::Pack(fbb, &src)); + + auto dst = + CppVecNativeTypeTest::UnPackContainer(fbb.GetBufferPointer()); + + TEST_EQ(dst->points.size(), static_cast(N)); + for (int i = 0; i < N; ++i) { + TEST_EQ(dst->points[i].x, 1.0f * i); + TEST_EQ(dst->points[i].y, 2.0f * i); + TEST_EQ(dst->points[i].z, 3.0f * i); + } +} + // Guard against -Wunused-function on platforms without file tests. #ifndef FLATBUFFERS_NO_FILE_TESTS // VS10 does not support typed enums, exclude from tests @@ -1877,6 +1909,7 @@ int FlatBufferTests(const std::string& tests_data_path) { FixedLengthArrayTest(); NativeTypeTest(); CppVecTypeTest(); + CppVecTypeNativeTypeTest(); OptionalScalarsTest(); ParseFlexbuffersFromJsonWithNullTest(); FlatbuffersSpanTest();