From 6c7ac8ea46634cd9642e5880daa67d7ef4f3b93d Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 19 Dec 2022 14:16:35 -0800 Subject: [PATCH] First steps towards a pure field generator interface. Currently, FieldGenerator holds onto a bit of state, and due to the way its interface is constructed it results in untracked dependencies between the contents of map values that get tossed around the compiler. In order to break these dependencies, we want to move calculation of string variables into a centrally tracked place, but that requires inserting variable setup and destruction code in each FieldGenerator call. Hence, FieldGenerator is replaced with a PIMPL wrapper (FieldGenWrapper) to allow us to do this. Followup CLs will: * Rename FieldGenWrapper to FieldGenerator and FieldGenerator to some interface-ey name. * Gradually morph the interface of FieldGenerator to encapsulate all per-field logic, so that message.cc does not have to iterate over fields except to call into generators, and as such does not need to manipulate per-field substitution variables. This CL is a no-op refactor. PiperOrigin-RevId: 496489306 --- src/file_lists.cmake | 67 ++- src/google/protobuf/compiler/cpp/field.cc | 101 ++-- src/google/protobuf/compiler/cpp/field.h | 437 +++++++++++------- src/google/protobuf/compiler/cpp/message.cc | 35 +- .../protobuf/compiler/cpp/primitive_field.cc | 6 - .../protobuf/compiler/cpp/primitive_field.h | 6 +- .../protobuf/compiler/cpp/string_field.cc | 6 - .../protobuf/compiler/cpp/string_field.h | 6 +- 8 files changed, 373 insertions(+), 291 deletions(-) diff --git a/src/file_lists.cmake b/src/file_lists.cmake index bb4114cee7..e903305820 100644 --- a/src/file_lists.cmake +++ b/src/file_lists.cmake @@ -1,4 +1,4 @@ -# Auto-generated by @//pkg:gen_src_file_lists_cmake +# Auto-generated by //pkg:gen_src_file_lists_cmake # # This file contains lists of sources based on Bazel rules. It should # be included from a hand-written CMake file that defines targets. @@ -9,7 +9,7 @@ if(${CMAKE_VERSION} VERSION_GREATER 3.10 OR ${CMAKE_VERSION} VERSION_EQUAL 3.10) include_guard() endif() -# @//pkg:protobuf +# //pkg:protobuf set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.cc @@ -85,7 +85,7 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc ) -# @//pkg:protobuf +# //pkg:protobuf set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.h ${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.h @@ -192,7 +192,7 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h ) -# @//pkg:protobuf_lite +# //pkg:protobuf_lite set(libprotobuf_lite_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc @@ -220,7 +220,7 @@ set(libprotobuf_lite_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc ) -# @//pkg:protobuf_lite +# //pkg:protobuf_lite set(libprotobuf_lite_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h @@ -270,7 +270,7 @@ set(libprotobuf_lite_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h ) -# @//pkg:protoc +# //pkg:protoc set(libprotoc_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc @@ -366,7 +366,7 @@ set(libprotoc_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc ) -# @//pkg:protoc +# //pkg:protoc set(libprotoc_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h @@ -388,7 +388,6 @@ set(libprotoc_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/primitive_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/service.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/string_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/tracker.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -470,7 +469,7 @@ set(libprotoc_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.h ) -# @//src/google/protobuf:well_known_type_protos +# //src/google/protobuf:well_known_type_protos set(wkt_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/any.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/api.proto @@ -484,68 +483,68 @@ set(wkt_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.proto ) -# @//src/google/protobuf:descriptor_proto +# //src/google/protobuf:descriptor_proto set(descriptor_proto_proto_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto ) -# @//src/google/protobuf:descriptor_proto +# //src/google/protobuf:descriptor_proto set(descriptor_proto_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.cc ) -# @//src/google/protobuf:descriptor_proto +# //src/google/protobuf:descriptor_proto set(descriptor_proto_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.h ) -# @//src/google/protobuf:descriptor_proto +# //src/google/protobuf:descriptor_proto set(descriptor_proto_files ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_proto-descriptor-set.proto.bin ) -# @//src/google/protobuf/compiler:plugin_proto +# //src/google/protobuf/compiler:plugin_proto set(plugin_proto_proto_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto ) -# @//src/google/protobuf/compiler:plugin_proto +# //src/google/protobuf/compiler:plugin_proto set(plugin_proto_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.cc ) -# @//src/google/protobuf/compiler:plugin_proto +# //src/google/protobuf/compiler:plugin_proto set(plugin_proto_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.h ) -# @//src/google/protobuf/compiler:plugin_proto +# //src/google/protobuf/compiler:plugin_proto set(plugin_proto_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin_proto-descriptor-set.proto.bin ) -# @//pkg:common_test +# //pkg:common_test set(common_test_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.cc ) -# @//pkg:common_test +# //pkg:common_test set(common_test_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.h ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.h ) -# @//pkg:lite_test_util +# //pkg:lite_test_util set(lite_test_util_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.cc ) -# @//pkg:lite_test_util +# //pkg:lite_test_util set(lite_test_util_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.h @@ -556,14 +555,14 @@ set(lite_test_util_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h ) -# @//pkg:test_util +# //pkg:test_util set(test_util_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc ) -# @//pkg:test_util +# //pkg:test_util set(test_util_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/unittest.h @@ -578,7 +577,7 @@ set(test_util_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc ) -# @//src/google/protobuf:full_test_srcs +# //src/google/protobuf:full_test_srcs set(protobuf_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align_test.cc @@ -610,7 +609,7 @@ set(protobuf_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.cc ) -# @//src/google/protobuf:test_proto_srcs +# //src/google/protobuf:test_proto_srcs set(protobuf_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/map_proto2_unittest.proto @@ -643,13 +642,13 @@ set(protobuf_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_well_known_types.proto ) -# @//src/google/protobuf:lite_test_srcs +# //src/google/protobuf:lite_test_srcs set(protobuf_lite_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/lite_arena_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/lite_unittest.cc ) -# @//src/google/protobuf:lite_test_proto_srcs +# //src/google/protobuf:lite_test_proto_srcs set(protobuf_lite_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_unittest.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import_lite.proto @@ -657,7 +656,7 @@ set(protobuf_lite_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lite.proto ) -# @//src/google/protobuf/compiler:test_srcs +# //src/google/protobuf/compiler:test_srcs set(compiler_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc @@ -680,18 +679,18 @@ set(compiler_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc ) -# @//src/google/protobuf/compiler:test_proto_srcs +# //src/google/protobuf/compiler:test_proto_srcs set(compiler_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_large_enum_value.proto ) -# @//src/google/protobuf/compiler:test_plugin_srcs +# //src/google/protobuf/compiler:test_plugin_srcs set(test_plugin_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/test_plugin.cc ) -# @//src/google/protobuf/io:test_srcs +# //src/google/protobuf/io:test_srcs set(io_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32_unittest.cc @@ -702,7 +701,7 @@ set(io_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_unittest.cc ) -# @//src/google/protobuf/util:test_srcs +# //src/google/protobuf/util:test_srcs set(util_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator_test.cc @@ -712,14 +711,14 @@ set(util_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util_test.cc ) -# @//src/google/protobuf/util:test_proto_srcs +# //src/google/protobuf/util:test_proto_srcs set(util_test_protos_files ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format_proto3.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.proto ) -# @//src/google/protobuf/stubs:test_srcs +# //src/google/protobuf/stubs:test_srcs set(stubs_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/common_unittest.cc ) diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc index 523426b049..891d819546 100644 --- a/src/google/protobuf/compiler/cpp/field.cc +++ b/src/google/protobuf/compiler/cpp/field.cc @@ -167,8 +167,8 @@ void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) { "u"); } -void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const { - Formatter format(printer, variables_); +void FieldGenerator::GenerateAggregateInitializer(io::Printer* p) const { + Formatter format(p, variables_); if (ShouldSplit(descriptor_, options_)) { format("decltype(Impl_::Split::$name$_){arena}"); return; @@ -177,110 +177,97 @@ void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const { } void FieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); + io::Printer* p) const { + Formatter format(p, variables_); format("/*decltype($field$)*/{}"); } -void FieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); +void FieldGenerator::GenerateCopyAggregateInitializer(io::Printer* p) const { + Formatter format(p, variables_); format("decltype($field$){from.$field$}"); } -void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const { +void FieldGenerator::GenerateCopyConstructorCode(io::Printer* p) const { if (ShouldSplit(descriptor_, options_)) { // There is no copy constructor for the `Split` struct, so we need to copy // the value here. - Formatter format(printer, variables_); + Formatter format(p, variables_); format("$field$ = from.$field$;\n"); } } -void FieldGenerator::GenerateIfHasField(io::Printer* printer) const { +void FieldGenerator::GenerateIfHasField(io::Printer* p) const { GOOGLE_ABSL_CHECK(internal::cpp::HasHasbit(descriptor_)); GOOGLE_ABSL_CHECK(variables_.find("has_hasbit") != variables_.end()); - Formatter format(printer, variables_); + Formatter format(p, variables_); format("if (($has_hasbit$) != 0) {\n"); } -FieldGenerator::~FieldGenerator() {} - -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) - : descriptor_(descriptor), field_generators_(descriptor->field_count()) { - // Construct all the FieldGenerators. - for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset( - MakeGenerator(descriptor->field(i), options, scc_analyzer)); - } -} - -FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator( - const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - - return nullptr; -} - -FieldGenerator* FieldGeneratorMap::MakeGenerator( +namespace { +std::unique_ptr MakeGenerator( const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer) { - FieldGenerator* generator = - MakeGoogleInternalGenerator(field, options, scc_analyzer); - if (generator) { - return generator; - } - if (field->is_repeated()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: if (field->is_map()) { - return new MapFieldGenerator(field, options, scc_analyzer); + return absl::make_unique(field, options, + scc_analyzer); } else { - return new RepeatedMessageFieldGenerator(field, options, - scc_analyzer); + return absl::make_unique( + field, options, scc_analyzer); } case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field, options); + return absl::make_unique(field, options); case FieldDescriptor::CPPTYPE_ENUM: - return new RepeatedEnumFieldGenerator(field, options); + return absl::make_unique(field, options); default: - return new RepeatedPrimitiveFieldGenerator(field, options); + return absl::make_unique(field, + options); } } else if (field->real_containing_oneof()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageOneofFieldGenerator(field, options, scc_analyzer); + return absl::make_unique(field, options, + scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: - return new StringOneofFieldGenerator(field, options); + return absl::make_unique(field, options); case FieldDescriptor::CPPTYPE_ENUM: - return new EnumOneofFieldGenerator(field, options); + return absl::make_unique(field, options); default: - return new PrimitiveOneofFieldGenerator(field, options); + return absl::make_unique(field, options); } } else { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field, options, scc_analyzer); + return absl::make_unique(field, options, + scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field, options); + return absl::make_unique(field, options); case FieldDescriptor::CPPTYPE_ENUM: - return new EnumFieldGenerator(field, options); + return absl::make_unique(field, options); default: - return new PrimitiveFieldGenerator(field, options); + return absl::make_unique(field, options); } } } +} // namespace -FieldGeneratorMap::~FieldGeneratorMap() {} +FieldGenWrapper::FieldGenWrapper(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : impl_(MakeGenerator(field, options, scc_analyzer)) {} -const FieldGenerator& FieldGeneratorMap::get( - const FieldDescriptor* field) const { - GOOGLE_ABSL_CHECK_EQ(field->containing_type(), descriptor_); - return *field_generators_[field->index()]; +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : descriptor_(descriptor) { + // Construct all the FieldGenerators. + fields_.reserve(descriptor->field_count()); + for (const auto* field : internal::FieldRange(descriptor)) { + fields_.emplace_back(field, options, scc_analyzer); + } } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field.h b/src/google/protobuf/compiler/cpp/field.h index 2b97272273..29d3ce81a2 100644 --- a/src/google/protobuf/compiler/cpp/field.h +++ b/src/google/protobuf/compiler/cpp/field.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "google/protobuf/descriptor.h" #include "absl/container/flat_hash_map.h" @@ -45,178 +46,73 @@ #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google - namespace google { namespace protobuf { namespace compiler { namespace cpp { -absl::flat_hash_map FieldVars( - const FieldDescriptor* desc, const Options& opts); - -absl::flat_hash_map OneofFieldVars( - const FieldDescriptor* descriptor); - -// Helper function: set variables in the map that are the same for all -// field code generators. -// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', -// 'deprecation']. -void SetCommonFieldVariables( - const FieldDescriptor* descriptor, - absl::flat_hash_map* variables, - const Options& options); - -void SetCommonOneofFieldVariables( - const FieldDescriptor* descriptor, - absl::flat_hash_map* variables); - +// Customization points for each field codegen type. See FieldGenWrapper to +// see how each of these functions is used. class FieldGenerator { public: explicit FieldGenerator(const FieldDescriptor* descriptor, const Options& options) : descriptor_(descriptor), options_(options) {} + FieldGenerator(const FieldGenerator&) = delete; FieldGenerator& operator=(const FieldGenerator&) = delete; - virtual ~FieldGenerator(); - virtual void GenerateSerializeWithCachedSizes( - io::Printer* printer) const final{}; - // Generate lines of code declaring members fields of the message class - // needed to represent this field. These are placed inside the message - // class. - virtual void GeneratePrivateMembers(io::Printer* printer) const = 0; - - // Generate static default variable for this field. These are placed inside - // the message class. Most field types don't need this, so the default - // implementation is empty. - virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {} - - // Generate prototypes for all of the accessor functions related to this - // field. These are placed inside the class definition. - virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; - - // Generate inline definitions of accessor functions for this field. - // These are placed inside the header after all class definitions. - virtual void GenerateInlineAccessorDefinitions( - io::Printer* printer) const = 0; - - // Generate definitions of accessors that aren't inlined. These are - // placed somewhere in the .cc file. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateNonInlineAccessorDefinitions( - io::Printer* /*printer*/) const {} - - // Generate declarations of accessors that are for internal purposes only. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateInternalAccessorDefinitions( - io::Printer* /*printer*/) const {} - - // Generate definitions of accessors that are for internal purposes only. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateInternalAccessorDeclarations( - io::Printer* /*printer*/) const {} - - // Generate lines of code (statements, not declarations) which clear the - // field. This is used to define the clear_$name$() method - virtual void GenerateClearingCode(io::Printer* printer) const = 0; - - // Generate lines of code (statements, not declarations) which clear the - // field as part of the Clear() method for the whole message. For message - // types which have field presence bits, MessageGenerator::GenerateClear - // will have already checked the presence bits. - // - // Since most field types can re-use GenerateClearingCode, this method is - // not pure virtual. - virtual void GenerateMessageClearingCode(io::Printer* printer) const { - GenerateClearingCode(printer); + + virtual ~FieldGenerator() = 0; + + virtual void GeneratePrivateMembers(io::Printer* p) const = 0; + + virtual void GenerateStaticMembers(io::Printer* p) const {} + + virtual void GenerateAccessorDeclarations(io::Printer* p) const = 0; + + virtual void GenerateInlineAccessorDefinitions(io::Printer* p) const = 0; + + virtual void GenerateNonInlineAccessorDefinitions(io::Printer* p) const {} + + virtual void GenerateInternalAccessorDefinitions(io::Printer* p) const {} + + virtual void GenerateInternalAccessorDeclarations(io::Printer* p) const {} + + virtual void GenerateClearingCode(io::Printer* p) const = 0; + + virtual void GenerateMessageClearingCode(io::Printer* p) const { + GenerateClearingCode(p); } - // Generate lines of code (statements, not declarations) which merges the - // contents of the field from the current message to the target message, - // which is stored in the generated code variable "from". - // This is used to fill in the MergeFrom method for the whole message. - // Details of this usage can be found in message.cc under the - // GenerateMergeFrom method. - virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateMergingCode(io::Printer* p) const = 0; - // Generates a copy constructor - virtual void GenerateCopyConstructorCode(io::Printer* printer) const; + virtual void GenerateCopyConstructorCode(io::Printer* p) const; - // Generate lines of code (statements, not declarations) which swaps - // this field and the corresponding field of another message, which - // is stored in the generated code variable "other". This is used to - // define the Swap method. Details of usage can be found in - // message.cc under the GenerateSwap method. - virtual void GenerateSwappingCode(io::Printer* printer) const = 0; + virtual void GenerateSwappingCode(io::Printer* p) const = 0; - // Generate initialization code for private members declared by - // GeneratePrivateMembers(). These go into the message class's SharedCtor() - // method, invoked by each of the generated constructors. - virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + virtual void GenerateConstructorCode(io::Printer* p) const = 0; - // Generate any code that needs to go in the class's SharedDtor() method, - // invoked by the destructor. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {} - - // Generate a manual destructor invocation for use when the message is on an - // arena. The code that this method generates will be executed inside a - // shared-for-the-whole-message-class method registered with - // OwnDestructor(). - virtual void GenerateArenaDestructorCode(io::Printer* printer) const { + virtual void GenerateDestructorCode(io::Printer* p) const {} + + virtual void GenerateArenaDestructorCode(io::Printer* p) const { GOOGLE_ABSL_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone) << descriptor_->cpp_type_name(); } - // Generate initialization code for private members declared by - // GeneratePrivateMembers(). These go into the SharedCtor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `decltype($field$){$default$}`). Does not include `:` or `,` - // separators. Default values should be specified here when possible. - // - // Note: We use `decltype($field$)` for both explicit construction and the - // fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed - // in aggregate initialization so a valid copy/move constructor must exist - // (even though it's not used). Because of this, we need to comment out the - // decltype and fallback to implicit construction. - virtual void GenerateAggregateInitializer(io::Printer* printer) const; - - // Generate constinit initialization code for private members declared by - // GeneratePrivateMembers(). These go into the constexpr constructor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `/*decltype($field$)*/{}`, see above). Does not - // include `:` or `,` separators. - virtual void GenerateConstexprAggregateInitializer( - io::Printer* printer) const; - - // Generate copy initialization code for private members declared by - // GeneratePrivateMembers(). These go into the copy constructor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `decltype($field$){from.$field$}`, see above). Does not - // include `:` or `,` separators. - virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const; - - // Generate lines to serialize this field directly to the array "target", - // which are placed within the message's SerializeWithCachedSizesToArray() - // method. This must also advance "target" past the written bytes. + virtual void GenerateAggregateInitializer(io::Printer* p) const; + + virtual void GenerateConstexprAggregateInitializer(io::Printer* p) const; + + virtual void GenerateCopyAggregateInitializer(io::Printer* p) const; + virtual void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const = 0; + io::Printer* p) const = 0; - // Generate lines to compute the serialized size of this field, which - // are placed in the message's ByteSize() method. - virtual void GenerateByteSize(io::Printer* printer) const = 0; + virtual void GenerateByteSize(io::Printer* p) const = 0; - // Generates lines to call IsInitialized() for eligible message fields. Non - // message fields won't need to override this function. - virtual void GenerateIsInitialized(io::Printer* printer) const {} + virtual void GenerateIsInitialized(io::Printer* p) const {} - virtual void GenerateIfHasField(io::Printer* printer) const; + virtual void GenerateIfHasField(io::Printer* p) const; virtual bool IsInlined() const { return false; } @@ -228,46 +124,267 @@ class FieldGenerator { void SetInlinedStringIndex(int32_t inlined_string_index); protected: + // TODO(b/245791219): Remove these members and make this a pure interface. const FieldDescriptor* descriptor_; const Options& options_; absl::flat_hash_map variables_; }; +inline FieldGenerator::~FieldGenerator() = default; + +class FieldGenWrapper { + public: + FieldGenWrapper(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + + FieldGenWrapper(const FieldGenWrapper&) = delete; + FieldGenWrapper& operator=(const FieldGenWrapper&) = delete; + FieldGenWrapper(FieldGenWrapper&&) = default; + FieldGenWrapper& operator=(FieldGenWrapper&&) = default; + + // Prints private members needed to represent this field. + // + // These are placed inside the class definition. + void GeneratePrivateMembers(io::Printer* p) const { + impl_->GeneratePrivateMembers(p); + } + + // Prints static members needed to represent this field. + // + // These are placed inside the class definition. + void GenerateStaticMembers(io::Printer* p) const { + impl_->GenerateStaticMembers(p); + } + + // Generates declarations for all of the accessor functions related to this + // field. + // + // These are placed inside the class definition. + void GenerateAccessorDeclarations(io::Printer* p) const { + impl_->GenerateAccessorDeclarations(p); + } + + // Generates inline definitions of accessor functions for this field. + // + // These are placed in namespace scope in the header after all class + // definitions. + void GenerateInlineAccessorDefinitions(io::Printer* p) const { + impl_->GenerateInlineAccessorDefinitions(p); + } + + // Generates definitions of accessors that aren't inlined. + // + // These are placed in namespace scope in the .cc file. + void GenerateNonInlineAccessorDefinitions(io::Printer* p) const { + impl_->GenerateNonInlineAccessorDefinitions(p); + } + + // Generates declarations of accessors that are for internal purposes only. + void GenerateInternalAccessorDefinitions(io::Printer* p) const { + impl_->GenerateInternalAccessorDefinitions(p); + } + + // Generates definitions of accessors that are for internal purposes only. + void GenerateInternalAccessorDeclarations(io::Printer* p) const { + impl_->GenerateInternalAccessorDeclarations(p); + } + + // Generates statements which clear the field. + // + // This is used to define the clear_$name$() method. + void GenerateClearingCode(io::Printer* p) const { + impl_->GenerateClearingCode(p); + } + + // Generates statements which clear the field as part of the Clear() method + // for the whole message. + // + // For message types which have field presence bits, + // MessageGenerator::GenerateClear will have already checked the presence + // bits. + void GenerateMessageClearingCode(io::Printer* p) const { + impl_->GenerateMessageClearingCode(p); + } + + // Generates statements which merge the contents of the field from the current + // message to the target message, which is stored in the generated code + // variable `from`. + // + // This is used to fill in the MergeFrom method for the whole message. + // + // Details of this usage can be found in message.cc under the + // GenerateMergeFrom method. + void GenerateMergingCode(io::Printer* p) const { + impl_->GenerateMergingCode(p); + } + + // Generates a copy constructor + // + // TODO(b/245791219): Document this properly. + void GenerateCopyConstructorCode(io::Printer* p) const { + impl_->GenerateCopyConstructorCode(p); + } + + // Generates statements which swap this field and the corresponding field of + // another message, which is stored in the generated code variable `other`. + // + // This is used to define the Swap method. Details of usage can be found in + // message.cc under the GenerateSwap method. + void GenerateSwappingCode(io::Printer* p) const { + impl_->GenerateSwappingCode(p); + } + + // Generates initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the message class's SharedCtor() method, invoked by each of + // the generated constructors. + void GenerateConstructorCode(io::Printer* p) const { + impl_->GenerateConstructorCode(p); + } + + // Generates any code that needs to go in the class's SharedDtor() method, + // invoked by the destructor. + void GenerateDestructorCode(io::Printer* p) const { + impl_->GenerateDestructorCode(p); + } + + // Generates a manual destructor invocation for use when the message is on an + // arena. + // + // The code that this method generates will be executed inside a + // shared-for-the-whole-message-class method registered with OwnDestructor(). + void GenerateArenaDestructorCode(io::Printer* p) const { + impl_->GenerateArenaDestructorCode(p); + } + + // Generates initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the SharedCtor's aggregate initialization of the _impl_ + // struct and must follow the syntax `decltype($field$){$default$}`. + // Does not include `:` or `,` separators. Default values should be specified + // here when possible. + // + // NOTE: We use `decltype($field$)` for both explicit construction and the + // fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed + // in aggregate initialization so a valid copy/move constructor must exist + // (even though it's not used). Because of this, we need to comment out the + // decltype and fallback to implicit construction. + void GenerateAggregateInitializer(io::Printer* p) const { + impl_->GenerateAggregateInitializer(p); + } + + // Generates constinit initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the constexpr constructor's aggregate initialization of the + // _impl_ struct and must follow the syntax `/*decltype($field$)*/{}` (see + // above). Does not include `:` or `,` separators. + void GenerateConstexprAggregateInitializer(io::Printer* p) const { + impl_->GenerateConstexprAggregateInitializer(p); + } + + // Generates copy initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the copy constructor's aggregate initialization of the _impl_ + // struct and must follow the syntax `decltype($field$){from.$field$}` (see + // above). Does not include `:` or `,` separators. + void GenerateCopyAggregateInitializer(io::Printer* p) const { + impl_->GenerateCopyAggregateInitializer(p); + } + + // Generates statements to serialize this field directly to the array + // `target`, which are placed within the message's + // SerializeWithCachedSizesToArray() method. + // + // This must also advance `target` past the written bytes. + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const { + impl_->GenerateSerializeWithCachedSizesToArray(p); + } + + // Generates statements to compute the serialized size of this field, which + // are placed in the message's ByteSize() method. + void GenerateByteSize(io::Printer* p) const { impl_->GenerateByteSize(p); } + + // Generates lines to call IsInitialized() for eligible message fields. Non + // message fields won't need to override this function. + void GenerateIsInitialized(io::Printer* p) const { + impl_->GenerateIsInitialized(p); + } + + // TODO(b/245791219): Document this properly. + void GenerateIfHasField(io::Printer* p) const { + impl_->GenerateIfHasField(p); + } + + // TODO(b/245791219): Document this properly. + bool IsInlined() const { return impl_->IsInlined(); } + + // TODO(b/245791219): Document this properly. + ArenaDtorNeeds NeedsArenaDestructor() const { + return impl_->NeedsArenaDestructor(); + } + + private: + friend class FieldGeneratorMap; + std::unique_ptr impl_; +}; + // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: FieldGeneratorMap(const Descriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); + FieldGeneratorMap(const FieldGeneratorMap&) = delete; FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete; - ~FieldGeneratorMap(); - const FieldGenerator& get(const FieldDescriptor* field) const; + const FieldGenWrapper& get(const FieldDescriptor* field) const { + GOOGLE_ABSL_CHECK_EQ(field->containing_type(), descriptor_); + return fields_[field->index()]; + } - void SetHasBitIndices(const std::vector& has_bit_indices_) { + void SetHasBitIndices(absl::Span has_bit_indices) { for (int i = 0; i < descriptor_->field_count(); ++i) { - field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]); + fields_[i].impl_->SetHasBitIndex(has_bit_indices[i]); } } - void SetInlinedStringIndices(const std::vector& inlined_string_indices) { + void SetInlinedStringIndices(absl::Span inlined_string_indices) { for (int i = 0; i < descriptor_->field_count(); ++i) { - field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]); + fields_[i].impl_->SetInlinedStringIndex(inlined_string_indices[i]); } } private: const Descriptor* descriptor_; - std::vector> field_generators_; - - static FieldGenerator* MakeGoogleInternalGenerator( - const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - static FieldGenerator* MakeGenerator(const FieldDescriptor* field, - const Options& options, - MessageSCCAnalyzer* scc_analyzer); + std::vector fields_; }; +// Helper function: set variables in the map that are the same for all +// field code generators. +// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', +// 'deprecation']. +// +// Each function comes in a legacy "write variables to an existing variable +// map" and a new version that returns a new map object for use with WithVars(). + +absl::flat_hash_map FieldVars( + const FieldDescriptor* desc, const Options& opts); + +absl::flat_hash_map OneofFieldVars( + const FieldDescriptor* descriptor); + +void SetCommonFieldVariables( + const FieldDescriptor* descriptor, + absl::flat_hash_map* variables, + const Options& options); + +void SetCommonOneofFieldVariables( + const FieldDescriptor* descriptor, + absl::flat_hash_map* variables); } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index f641d9cba7..8670112c42 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -1799,10 +1799,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) { // Emit some private and static members for (auto field : optimized_order_) { - const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateStaticMembers(p); + field_generators_.get(field).GenerateStaticMembers(p); if (!ShouldSplit(field, options_)) { - generator.GeneratePrivateMembers(p); + field_generators_.get(field).GeneratePrivateMembers(p); } } if (ShouldSplit(descriptor_, options_)) { @@ -1810,8 +1809,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) { format.Indent(); for (auto field : optimized_order_) { if (!ShouldSplit(field, options_)) continue; - const FieldGenerator& generator = field_generators_.get(field); - generator.GeneratePrivateMembers(p); + field_generators_.get(field).GeneratePrivateMembers(p); } format.Outdent(); format( @@ -2503,8 +2501,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { for (auto field : optimized_order_) { if (IsFieldStripped(field, options_) || ShouldSplit(field, options_)) continue; - const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(p); + field_generators_.get(field).GenerateArenaDestructorCode(p); } if (ShouldSplit(descriptor_, options_)) { format("if (!_this->IsSplitMessageDefault()) {\n"); @@ -2512,8 +2509,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { for (auto field : optimized_order_) { if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_)) continue; - const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(p); + field_generators_.get(field).GenerateArenaDestructorCode(p); } format.Outdent(); format("}\n"); @@ -3405,7 +3401,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) { // Go back and emit merging code for each of the fields we processed. bool deferred_has_bit_changes = false; for (const auto field : chunk) { - const FieldGenerator& generator = field_generators_.get(field); + const auto& generator = field_generators_.get(field); if (field->is_repeated()) { generator.GenerateMergingCode(p); @@ -3617,8 +3613,6 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p, PrintFieldComment(format, field); } - const FieldGenerator& field_gen = field_generators_.get(field); - bool have_enclosing_if = false; if (field->options().weak()) { } else if (HasHasbit(field)) { @@ -3628,7 +3622,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p, if (cached_has_bits_index == has_bit_index / 32) { format("if (cached_has_bits & $has_mask$) {\n"); } else { - field_gen.GenerateIfHasField(p); + field_generators_.get(field).GenerateIfHasField(p); } format.Indent(); @@ -3637,7 +3631,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p, have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - field_gen.GenerateSerializeWithCachedSizesToArray(p); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); if (have_enclosing_if) { format.Outdent(); @@ -4063,12 +4057,11 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { format("::size_t total_size = 0;\n"); for (auto field : optimized_order_) { if (field->is_required()) { - const FieldGenerator& field_gen = field_generators_.get(field); format("\n"); - field_gen.GenerateIfHasField(p); + field_generators_.get(field).GenerateIfHasField(p); format.Indent(); PrintFieldComment(format, field); - field_gen.GenerateByteSize(p); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4122,10 +4115,9 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { for (auto field : optimized_order_) { if (!field->is_required()) continue; PrintFieldComment(format, field); - const FieldGenerator& field_gen = field_generators_.get(field); - field_gen.GenerateIfHasField(p); + field_generators_.get(field).GenerateIfHasField(p); format.Indent(); - field_gen.GenerateByteSize(p); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4180,7 +4172,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { // Go back and emit checks for each of the fields we processed. for (int j = 0; j < chunk.size(); j++) { const FieldDescriptor* field = chunk[j]; - const FieldGenerator& generator = field_generators_.get(field); bool have_enclosing_if = false; bool need_extra_newline = false; @@ -4198,7 +4189,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - generator.GenerateByteSize(p); + field_generators_.get(field).GenerateByteSize(p); if (have_enclosing_if) { format.Outdent(); diff --git a/src/google/protobuf/compiler/cpp/primitive_field.cc b/src/google/protobuf/compiler/cpp/primitive_field.cc index fa0a4d306b..8224cae7c3 100644 --- a/src/google/protobuf/compiler/cpp/primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/primitive_field.cc @@ -135,8 +135,6 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator( SetPrimitiveVariables(descriptor, &variables_, options); } -PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} - void PrimitiveFieldGenerator::GeneratePrivateMembers( io::Printer* printer) const { Formatter format(printer, variables_); @@ -264,8 +262,6 @@ PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( SetCommonOneofFieldVariables(descriptor, &variables_); } -PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} - void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( io::Printer* printer) const { Formatter format(printer, variables_); @@ -328,8 +324,6 @@ RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( } } -RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} - void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers( io::Printer* printer) const { Formatter format(printer, variables_); diff --git a/src/google/protobuf/compiler/cpp/primitive_field.h b/src/google/protobuf/compiler/cpp/primitive_field.h index 43ada6ff5d..445ba087ea 100644 --- a/src/google/protobuf/compiler/cpp/primitive_field.h +++ b/src/google/protobuf/compiler/cpp/primitive_field.h @@ -51,7 +51,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { const Options& options); PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete; PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete; - ~PrimitiveFieldGenerator() override; + ~PrimitiveFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -78,7 +78,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { PrimitiveOneofFieldGenerator(const PrimitiveOneofFieldGenerator&) = delete; PrimitiveOneofFieldGenerator& operator=(const PrimitiveOneofFieldGenerator&) = delete; - ~PrimitiveOneofFieldGenerator() override; + ~PrimitiveOneofFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -95,7 +95,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { delete; RepeatedPrimitiveFieldGenerator& operator=( const RepeatedPrimitiveFieldGenerator&) = delete; - ~RepeatedPrimitiveFieldGenerator() override; + ~RepeatedPrimitiveFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; diff --git a/src/google/protobuf/compiler/cpp/string_field.cc b/src/google/protobuf/compiler/cpp/string_field.cc index 0ddb8586dc..dc75f0fd3a 100644 --- a/src/google/protobuf/compiler/cpp/string_field.cc +++ b/src/google/protobuf/compiler/cpp/string_field.cc @@ -108,8 +108,6 @@ StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, SetStringVariables(descriptor, &variables_, options); } -StringFieldGenerator::~StringFieldGenerator() {} - void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { Formatter format(printer, variables_); if (!inlined_) { @@ -579,8 +577,6 @@ StringOneofFieldGenerator::StringOneofFieldGenerator( SetCommonOneofFieldVariables(descriptor, &variables_); } -StringOneofFieldGenerator::~StringOneofFieldGenerator() {} - void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( io::Printer* printer) const { Formatter format(printer, variables_); @@ -685,8 +681,6 @@ RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( SetStringVariables(descriptor, &variables_, options); } -RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} - void RepeatedStringFieldGenerator::GeneratePrivateMembers( io::Printer* printer) const { Formatter format(printer, variables_); diff --git a/src/google/protobuf/compiler/cpp/string_field.h b/src/google/protobuf/compiler/cpp/string_field.h index 1280fa08be..584c4c5d44 100644 --- a/src/google/protobuf/compiler/cpp/string_field.h +++ b/src/google/protobuf/compiler/cpp/string_field.h @@ -51,7 +51,7 @@ class StringFieldGenerator : public FieldGenerator { const Options& options); StringFieldGenerator(const StringFieldGenerator&) = delete; StringFieldGenerator& operator=(const StringFieldGenerator&) = delete; - ~StringFieldGenerator() override; + ~StringFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -89,7 +89,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { StringOneofFieldGenerator(const StringOneofFieldGenerator&) = delete; StringOneofFieldGenerator& operator=(const StringOneofFieldGenerator&) = delete; - ~StringOneofFieldGenerator() override; + ~StringOneofFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -109,7 +109,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { RepeatedStringFieldGenerator(const RepeatedStringFieldGenerator&) = delete; RepeatedStringFieldGenerator& operator=(const RepeatedStringFieldGenerator&) = delete; - ~RepeatedStringFieldGenerator() override; + ~RepeatedStringFieldGenerator() override = default; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override;