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 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 20:35:36 +02:00
parent 35665b5ae7
commit 19aa2ce420
6 changed files with 108 additions and 1 deletions

View File

@@ -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}")

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -0,0 +1,34 @@
#ifndef CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H
#define CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H
#include <vector>
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 <typename T>
struct CustomVec : public std::vector<T> {
using std::vector<T>::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

View File

@@ -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<Native::Vec3>");
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<size_t>(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();