From e673ba9691867bfe655589cb75eb8a05e7a20e19 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 27 Aug 2026 14:41:19 -0700 Subject: [PATCH] Fix C++ auto-increment macro symbol collisions --- crates/bindings-cpp/ARCHITECTURE.md | 10 ++++---- .../spacetimedb/table_with_constraints.h | 23 +++++++++++-------- .../cases/indexes/autoinc_schema_one.h | 10 ++++++++ .../cases/indexes/autoinc_schema_two.h | 10 ++++++++ .../cases/indexes/ok_autoinc_same_line.cpp | 6 +++++ .../tests/compile/run-compile-tests.ps1 | 1 + .../tests/compile/run-compile-tests.sh | 4 ++++ 7 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_one.h create mode 100644 crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_two.h create mode 100644 crates/bindings-cpp/tests/compile/cases/indexes/ok_autoinc_same_line.cpp diff --git a/crates/bindings-cpp/ARCHITECTURE.md b/crates/bindings-cpp/ARCHITECTURE.md index d5f74910d7f..98eb5729321 100644 --- a/crates/bindings-cpp/ARCHITECTURE.md +++ b/crates/bindings-cpp/ARCHITECTURE.md @@ -238,9 +238,9 @@ Auto-increment fields require special handling during `insert()` operations. Whe FIELD_PrimaryKeyAutoInc(users, id); // Generates both constraint registration AND auto-increment integration: -// 1. Auto-increment integration function (unique per field via __LINE__) +// 1. Auto-increment integration function (stable and scoped per table field) namespace SpacetimeDB { namespace detail { - static void autoinc_integrate_47(User& row, SpacetimeDB::bsatn::Reader& reader) { + static void autoinc_integrate_users_id(User& row, SpacetimeDB::bsatn::Reader& reader) { using FieldType = decltype(std::declval().id); FieldType generated_value = SpacetimeDB::bsatn::deserialize(reader); row.id = generated_value; // Update field with generated ID @@ -248,10 +248,10 @@ namespace SpacetimeDB { namespace detail { }} // 2. Registration function to register the integrator -extern "C" __attribute__((export_name("__preinit__19_autoinc_register_47"))) -void __preinit__19_autoinc_register_47() { +extern "C" __attribute__((export_name("__preinit__19_autoinc_register_users_id"))) +void __preinit__19_autoinc_register_users_id() { SpacetimeDB::detail::get_autoinc_integrator() = - &SpacetimeDB::detail::autoinc_integrate_47; + &SpacetimeDB::detail::autoinc_integrate_users_id; } ``` diff --git a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h index 5e62aff3eec..4ccc1f45a95 100644 --- a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h +++ b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h @@ -685,20 +685,23 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { // Auto-Increment Integration Helper // ============================================================================= -// Helper macro to register auto-increment integration function -// Creates a unique function and registers it for the struct type -#define SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(StructType, field_name) \ +// Helper macros to register an auto-increment integration function. +// Table and field names make the generated symbols stable and unique across headers. +#define SPACETIMEDB_AUTOINC_SYMBOL(prefix, table_name, field_name) \ + SPACETIMEDB_PASTE(prefix, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, field_name))) + +#define SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(table_name, StructType, field_name) \ namespace SpacetimeDB { namespace detail { \ - static void SPACETIMEDB_PASTE(autoinc_integrate_, __LINE__)(StructType& row, SpacetimeDB::bsatn::Reader& reader) { \ + static void SPACETIMEDB_AUTOINC_SYMBOL(autoinc_integrate_, table_name, field_name)(StructType& row, SpacetimeDB::bsatn::Reader& reader) { \ using FieldType = decltype(std::declval().field_name); \ FieldType generated_value = SpacetimeDB::bsatn::deserialize(reader); \ row.field_name = generated_value; \ } \ }} \ - extern "C" __attribute__((export_name("__preinit__19_autoinc_register_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ - void SPACETIMEDB_PASTE(__preinit__19_autoinc_register_, __LINE__)() { \ + extern "C" __attribute__((export_name("__preinit__19_autoinc_register_" #table_name "_" #field_name))) \ + void SPACETIMEDB_AUTOINC_SYMBOL(__preinit__19_autoinc_register_, table_name, field_name)() { \ SpacetimeDB::detail::get_autoinc_integrator() = \ - &SpacetimeDB::detail::SPACETIMEDB_PASTE(autoinc_integrate_, __LINE__); \ + &SpacetimeDB::detail::SPACETIMEDB_AUTOINC_SYMBOL(autoinc_integrate_, table_name, field_name); \ } // ============================================================================= @@ -782,7 +785,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { #table_name, #field_name, static_cast<::SpacetimeDB::FieldConstraint>( \ static_cast(::SpacetimeDB::FieldConstraint::PrimaryKey) | static_cast(::SpacetimeDB::FieldConstraint::AutoInc))); \ } \ - SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(typename std::remove_cv_t::type, field_name) + SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(table_name, typename std::remove_cv_t::type, field_name) #define FIELD_UniqueAutoInc(table_name, field_name) \ static_assert([]() constexpr { \ @@ -807,7 +810,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { #table_name, #field_name, static_cast<::SpacetimeDB::FieldConstraint>( \ static_cast(::SpacetimeDB::FieldConstraint::Unique) | static_cast(::SpacetimeDB::FieldConstraint::AutoInc))); \ } \ - SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(typename std::remove_cv_t::type, field_name) + SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(table_name, typename std::remove_cv_t::type, field_name) #define FIELD_IndexAutoInc(table_name, field_name) \ static_assert([]() constexpr { \ @@ -846,7 +849,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, ::SpacetimeDB::FieldConstraint::AutoInc); \ } \ - SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(typename std::remove_cv_t::type, field_name) + SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(table_name, typename std::remove_cv_t::type, field_name) #define SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) \ extern "C" __attribute__((export_name("__preinit__18_explicit_index_name_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ diff --git a/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_one.h b/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_one.h new file mode 100644 index 00000000000..b8263561849 --- /dev/null +++ b/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_one.h @@ -0,0 +1,10 @@ +#pragma once + +struct AutoIncSameLineOne { + uint64_t id; +}; + +SPACETIMEDB_STRUCT(AutoIncSameLineOne, id) +SPACETIMEDB_TABLE(AutoIncSameLineOne, autoinc_same_line_one, Public) +#line 100 +FIELD_PrimaryKeyAutoInc(autoinc_same_line_one, id) diff --git a/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_two.h b/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_two.h new file mode 100644 index 00000000000..eab7e222994 --- /dev/null +++ b/crates/bindings-cpp/tests/compile/cases/indexes/autoinc_schema_two.h @@ -0,0 +1,10 @@ +#pragma once + +struct AutoIncSameLineTwo { + uint64_t id; +}; + +SPACETIMEDB_STRUCT(AutoIncSameLineTwo, id) +SPACETIMEDB_TABLE(AutoIncSameLineTwo, autoinc_same_line_two, Public) +#line 100 +FIELD_PrimaryKeyAutoInc(autoinc_same_line_two, id) diff --git a/crates/bindings-cpp/tests/compile/cases/indexes/ok_autoinc_same_line.cpp b/crates/bindings-cpp/tests/compile/cases/indexes/ok_autoinc_same_line.cpp new file mode 100644 index 00000000000..99cc40deb37 --- /dev/null +++ b/crates/bindings-cpp/tests/compile/cases/indexes/ok_autoinc_same_line.cpp @@ -0,0 +1,6 @@ +#include "spacetimedb.h" + +using namespace SpacetimeDB; + +#include "autoinc_schema_one.h" +#include "autoinc_schema_two.h" diff --git a/crates/bindings-cpp/tests/compile/run-compile-tests.ps1 b/crates/bindings-cpp/tests/compile/run-compile-tests.ps1 index 71975a2ccb1..5059ed156b8 100644 --- a/crates/bindings-cpp/tests/compile/run-compile-tests.ps1 +++ b/crates/bindings-cpp/tests/compile/run-compile-tests.ps1 @@ -103,6 +103,7 @@ $cases = switch ($Suite) { "indexes" { @( (New-CompileCase "ok_multi_column_range_prefixes" "cases/indexes/ok_multi_column_range_prefixes.cpp" "success") + (New-CompileCase "ok_autoinc_same_line" "cases/indexes/ok_autoinc_same_line.cpp" "success") (New-CompileCase "error_multi_column_range_not_terminal" "cases/indexes/error_multi_column_range_not_terminal.cpp" "failure" "Range in a multi-column index filter must be the final supplied element") ) } diff --git a/crates/bindings-cpp/tests/compile/run-compile-tests.sh b/crates/bindings-cpp/tests/compile/run-compile-tests.sh index 78138b47ab4..65778c1f0c6 100644 --- a/crates/bindings-cpp/tests/compile/run-compile-tests.sh +++ b/crates/bindings-cpp/tests/compile/run-compile-tests.sh @@ -133,12 +133,16 @@ if [[ "$SUITE" == "http-handlers" ]]; then else declare -a CASE_NAMES=( "ok_multi_column_range_prefixes" + "ok_autoinc_same_line" "error_multi_column_range_not_terminal" ) CASE_EXPECTATION["ok_multi_column_range_prefixes"]="success" CASE_SOURCE["ok_multi_column_range_prefixes"]="$SCRIPT_DIR/cases/indexes/ok_multi_column_range_prefixes.cpp" + CASE_EXPECTATION["ok_autoinc_same_line"]="success" + CASE_SOURCE["ok_autoinc_same_line"]="$SCRIPT_DIR/cases/indexes/ok_autoinc_same_line.cpp" + CASE_EXPECTATION["error_multi_column_range_not_terminal"]="failure" CASE_MARKER["error_multi_column_range_not_terminal"]="Range in a multi-column index filter must be the final supplied element" CASE_SOURCE["error_multi_column_range_not_terminal"]="$SCRIPT_DIR/cases/indexes/error_multi_column_range_not_terminal.cpp"