From 22ca11f2442eb57f7585d0e5f00ccb3a7c880b8b Mon Sep 17 00:00:00 2001 From: Dave Allison Date: Thu, 20 Aug 2026 10:01:43 -0700 Subject: [PATCH] Fix protobuf copy move --- phaser/compiler/gen.cc | 1 + phaser/compiler/message_gen.cc | 28 ++++++++++++++++++++++++++++ phaser/compiler/message_gen.h | 1 + phaser/stress_test.cc | 16 ++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/phaser/compiler/gen.cc b/phaser/compiler/gen.cc index 716a5ed..6f68577 100644 --- a/phaser/compiler/gen.cc +++ b/phaser/compiler/gen.cc @@ -228,6 +228,7 @@ Generator::Generator(const google::protobuf::FileDescriptor* file, void Generator::GenerateHeaders(std::ostream& os, std::string* error) { os << "#pragma once\n"; os << "#include \"phaser/runtime/runtime.h\"\n"; + os << "#include \n"; if (frontend_style_ == FrontendStyle::kRos && UsesRos1Intrinsic(file_)) { os << "#include \"phaser/runtime/ros.h\"\n"; } diff --git a/phaser/compiler/message_gen.cc b/phaser/compiler/message_gen.cc index 5667c1b..6f1d1d7 100644 --- a/phaser/compiler/message_gen.cc +++ b/phaser/compiler/message_gen.cc @@ -910,6 +910,8 @@ absl::Status MessageGenerator::GenerateHeader(std::ostream& os) { if (IsRosFrontend()) { GenerateRosOwnerCopyMove(os, true); GeneratePublicFieldDeclarations(os); + } else { + GenerateProtobufCopyMove(os, true); } // Generate protobuf accessors. @@ -1030,6 +1032,30 @@ void MessageGenerator::GenerateRosOwnerCopyMove(std::ostream& os, bool decl) { os << "}\n\n"; } +void MessageGenerator::GenerateProtobufCopyMove(std::ostream& os, bool decl) { + if (IsRosFrontend()) { + return; + } + const std::string name = MessageName(message_); + if (decl) { + os << " " << name << "(const " << name << "& other) = default;\n"; + os << " " << name << "& operator=(const " << name + << "& other) = default;\n"; + os << " " << name << "(" << name << "&& other) noexcept = default;\n"; + os << " " << name << "& operator=(" << name << "&& other) noexcept;\n\n"; + return; + } + + os << name << "& " << name << "::operator=(" << name + << "&& other) noexcept {\n"; + os << " if (this != &other) {\n"; + os << " this->~" << name << "();\n"; + os << " new (this) " << name << "(std::move(other));\n"; + os << " }\n"; + os << " return *this;\n"; + os << "}\n\n"; +} + void MessageGenerator::GenerateSource(std::ostream& os) { for (const auto& nested : nested_message_gens_) { nested->GenerateSource(os); @@ -1038,6 +1064,8 @@ void MessageGenerator::GenerateSource(std::ostream& os) { GenerateConstructors(os, false); if (IsRosFrontend()) { GenerateRosOwnerCopyMove(os, false); + } else { + GenerateProtobufCopyMove(os, false); } // Generate creators. diff --git a/phaser/compiler/message_gen.h b/phaser/compiler/message_gen.h index 2742810..13be040 100644 --- a/phaser/compiler/message_gen.h +++ b/phaser/compiler/message_gen.h @@ -101,6 +101,7 @@ class MessageGenerator { void GeneratePublicFieldDeclarations(std::ostream& os); void GenerateRosOneofTypes(std::ostream& os); void GenerateRosOwnerCopyMove(std::ostream& os, bool decl); + void GenerateProtobufCopyMove(std::ostream& os, bool decl); void GenerateRosSyncToPayload(std::ostream& os); void GenerateProtobufAccessors(std::ostream& os); void GenerateFieldProtobufAccessors(std::ostream& os); diff --git a/phaser/stress_test.cc b/phaser/stress_test.cc index 70f326f..649c911 100644 --- a/phaser/stress_test.cc +++ b/phaser/stress_test.cc @@ -61,6 +61,22 @@ TEST(StressTest, DynamicExplicitBufferExpansion) { EXPECT_EQ("expand-me", msg.s()); } +TEST(StressTest, MoveAssignmentReplacesMessageStorage) { + TestMessage destination; + destination.set_x(1); + destination.set_s("destination"); + + TestMessage source = TestMessage::CreateDynamicMutable(512); + source.set_x(42); + source.set_s("source"); + + destination = std::move(source); + + EXPECT_EQ(destination.x(), 42); + EXPECT_EQ(destination.s(), "source"); + EXPECT_FALSE(source.IsBound()); +} + TEST(StressTest, AllocFailsAtStart) { auto status = ::phaser::NewDynamicBuffer( 1024, ::phaser::test::AllocUntilLimit(0),