diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc index 4b77480997..b80ab36f77 100644 --- a/src/google/protobuf/compiler/cpp/file.cc +++ b/src/google/protobuf/compiler/cpp/file.cc @@ -529,17 +529,6 @@ void FileGenerator::GenerateSourcePrelude(io::Printer* p) { } } -bool FileGenerator::IsFileDescriptorProto() const { - if (Namespace(file_, options_) != - absl::StrCat("::", ProtobufNamespace(options_))) { - return false; - } - for (int i = 0; i < file_->message_type_count(); ++i) { - if (file_->message_type(i)->name() == "FileDescriptorProto") return true; - } - return false; -} - void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { MessageGenerator* generator = message_generators_[idx].get(); @@ -580,7 +569,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { generator->GenerateConstexprConstructor(p); - if (IsFileDescriptorProto()) { + if (IsFileDescriptorProto(file_, options_)) { p->Emit( { {"type", DefaultInstanceType(generator->descriptor(), options_)}, @@ -1158,7 +1147,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) { // However, we must provide a way to force initialize the default instances // of FileDescriptorProto which will be used during registration of other // files. - if (IsFileDescriptorProto()) { + if (IsFileDescriptorProto(file_, options_)) { NamespaceOpener ns(p); ns.ChangeTo(absl::StrCat(ProtobufNamespace(options_), "::internal")); p->Emit( @@ -1306,7 +1295,7 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* p) { decl.second.PrintTopLevelDecl(p, options_); } - if (IsFileDescriptorProto()) { + if (IsFileDescriptorProto(file_, options_)) { ns.ChangeTo(absl::StrCat(ProtobufNamespace(options_), "::internal")); p->Emit(R"cc( //~ Emit wants an indented line, so give it a comment to strip. diff --git a/src/google/protobuf/compiler/cpp/file.h b/src/google/protobuf/compiler/cpp/file.h index 96cecd77d4..6514df048f 100644 --- a/src/google/protobuf/compiler/cpp/file.h +++ b/src/google/protobuf/compiler/cpp/file.h @@ -168,8 +168,6 @@ class FileGenerator { void GenerateProto2NamespaceEnumSpecializations(io::Printer* p); - bool IsFileDescriptorProto() const; - // Sometimes the names we use in a .proto file happen to be defined as // macros on some platforms (e.g., macro/minor used in plugin.proto are // defined as macros in sys/types.h on FreeBSD and a few other platforms). diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc index b1894cf063..80a3ca92d3 100644 --- a/src/google/protobuf/compiler/cpp/helpers.cc +++ b/src/google/protobuf/compiler/cpp/helpers.cc @@ -1648,6 +1648,17 @@ std::vector AnnotatedAccessors( return vars; } +bool IsFileDescriptorProto(const FileDescriptor* file, const Options& options) { + if (Namespace(file, options) != + absl::StrCat("::", ProtobufNamespace(options))) { + return false; + } + for (int i = 0; i < file->message_type_count(); ++i) { + if (file->message_type(i)->name() == "FileDescriptorProto") return true; + } + return false; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h index 314d5a7034..6f5cf1808a 100644 --- a/src/google/protobuf/compiler/cpp/helpers.h +++ b/src/google/protobuf/compiler/cpp/helpers.h @@ -1049,6 +1049,11 @@ std::vector AnnotatedAccessors( absl::optional semantic = absl::nullopt); +// Check whether `file` represents the .proto file FileDescriptorProto and +// friends. This file needs special handling because it must be usable during +// dynamic initialization. +bool IsFileDescriptorProto(const FileDescriptor* file, const Options& options); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index a0773f0bac..b28e3b6b82 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -406,9 +406,16 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { // unknown fields and potentially an extension range. auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_); format( - "constexpr ::_pbi::TcParseTable<$1$, $2$, $3$, $4$, $5$> " + "$1$ ::_pbi::TcParseTable<$2$, $3$, $4$, $5$, $6$> " "$classname$::_table_ = " "{\n", + // FileDescriptorProto's table must be constant initialized. For MSVC this + // means using `constexpr`. However, we can't use `constexpr` for all + // tables because it breaks when crossing DLL boundaries. + // FileDescriptorProto is safe from this. + IsFileDescriptorProto(descriptor_->file(), options_) + ? "constexpr" + : "PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\nconst", tc_table_info_->table_size_log2, ordered_fields_.size(), tc_table_info_->aux_entries.size(), FieldNameDataSize(tc_table_info_->field_name_data),