aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorGravatar Bo Yang <teboring@google.com>2015-05-21 14:28:59 -0700
committerGravatar Bo Yang <teboring@google.com>2015-05-21 19:32:02 -0700
commit5db217305f37a79eeccd70f000088a06ec82fcec (patch)
treebe53dcf0c0b47ef9178ab8a6fa5c1946ee84a28f /src/google/protobuf/compiler/cpp
parent56095026ccc2f755a6fdb296e30c3ddec8f556a2 (diff)
down-integrate internal changes
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h26
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc505
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h29
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc59
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h21
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc688
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h25
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc33
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc16
-rw-r--r--src/google/protobuf/compiler/cpp/test_large_enum_value.proto43
20 files changed, 1137 insertions, 412 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 3eb20ab1..70d3a600 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -70,12 +70,23 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
EnumGenerator::~EnumGenerator() {}
+void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) {
+ if (!options_.proto_h) {
+ return;
+ }
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ printer->Print(vars, "enum $classname$ : int;\n");
+ printer->Print(vars, "bool $classname$_IsValid(int value);\n");
+}
+
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
vars["short_name"] = descriptor_->name();
+ vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
- printer->Print(vars, "enum $classname$ {\n");
+ printer->Print(vars, "enum $enumbase$ {\n");
printer->Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
@@ -90,7 +101,6 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
vars["prefix"] = (descriptor_->containing_type() == NULL) ?
"" : classname_ + "_";
-
if (i > 0) printer->Print(",\n");
printer->Print(vars, "$prefix$$name$ = $number$");
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 1ebd7cf7..3e930856 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -60,6 +60,12 @@ class EnumGenerator {
// Header stuff.
+ // Generate header code to forward-declare the enum. This is for use when
+ // generating other .proto.h files. This code should be placed within the
+ // enum's package namespace, but NOT within any class, even for nested
+ // enums.
+ void GenerateForwardDeclaration(io::Printer* printer);
+
// Generate header code defining the enum. This code should be placed
// within the enum's package namespace, but NOT within any class, even for
// nested enums.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 74989703..965327b1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -242,7 +242,7 @@ void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField<int> $name$_;\n");
- if (descriptor_->options().packed()
+ if (descriptor_->is_packed()
&& HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
@@ -352,7 +352,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
- if (!descriptor_->options().packed()) {
+ if (!descriptor_->is_packed()) {
// This path is rarely executed, so we use a non-inlined implementation.
if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
@@ -419,7 +419,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -432,7 +432,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
" this->$name$(i), output);\n");
@@ -446,7 +446,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -460,7 +460,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
" this->$name$(i), target);\n");
@@ -484,7 +484,7 @@ GenerateByteSize(io::Printer* printer) const {
" this->$name$(i));\n"
"}\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index cd2b6b75..1d7f8233 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -82,12 +82,38 @@ class FieldGenerator {
// implementation is empty.
virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
+ // Generate prototypes for accessors that will manipulate imported
+ // messages inline. These are for .proto.h headers.
+ //
+ // In .proto.h mode, the headers of imports are not #included. However,
+ // functions that manipulate the imported message types need access to
+ // the class definition of the imported message, meaning that the headers
+ // must be #included. To get around this, functions that manipulate
+ // imported message objects are defined as dependent functions in a base
+ // template class. By making them dependent template functions, the
+ // function templates will not be instantiated until they are called, so
+ // we can defer to those translation units to #include the necessary
+ // generated headers.
+ //
+ // See:
+ // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
+ //
+ // Most field types don't need this, so the default implementation is empty.
+ virtual void GenerateDependentAccessorDeclarations(
+ 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 depenent accessor functions for this field.
+ // These are placed inside the header after all class definitions.
+ virtual void GenerateDependentInlineAccessorDefinitions(
+ io::Printer* printer) const {}
+
// Generate inline definitions of accessor functions for this field.
// These are placed inside the header after all class definitions.
+ // In non-.proto.h mode, this generates dependent accessor functions as well.
virtual void GenerateInlineAccessorDefinitions(
io::Printer* printer, bool is_inline) const = 0;
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index a98c7d92..b997a51a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -94,113 +94,10 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
FileGenerator::~FileGenerator() {}
void FileGenerator::GenerateHeader(io::Printer* printer) {
- string filename_identifier = FilenameIdentifier(file_->name());
-
- // Generate top of header.
- printer->Print(
- "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "// source: $filename$\n"
- "\n"
- "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
- "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
- "\n"
- "#include <string>\n"
- "\n",
- "filename", file_->name(),
- "filename_identifier", filename_identifier);
-
-
- printer->Print(
- "#include <google/protobuf/stubs/common.h>\n"
- "\n");
-
- // Verify the protobuf library header version is compatible with the protoc
- // version before going any further.
- printer->Print(
- "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
- "#error This file was generated by a newer version of protoc which is\n"
- "#error incompatible with your Protocol Buffer headers. Please update\n"
- "#error your headers.\n"
- "#endif\n"
- "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
- "#error This file was generated by an older version of protoc which is\n"
- "#error incompatible with your Protocol Buffer headers. Please\n"
- "#error regenerate this file with a newer version of protoc.\n"
- "#endif\n"
- "\n",
- "min_header_version",
- SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
- "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
-
- // OK, it's now safe to #include other files.
- printer->Print(
- "#include <google/protobuf/arena.h>\n"
- "#include <google/protobuf/arenastring.h>\n"
- "#include <google/protobuf/generated_message_util.h>\n");
- if (UseUnknownFieldSet(file_)) {
- printer->Print(
- "#include <google/protobuf/metadata.h>\n");
- }
- if (file_->message_type_count() > 0) {
- if (HasDescriptorMethods(file_)) {
- printer->Print(
- "#include <google/protobuf/message.h>\n");
- } else {
- printer->Print(
- "#include <google/protobuf/message_lite.h>\n");
- }
- }
- printer->Print(
- "#include <google/protobuf/repeated_field.h>\n"
- "#include <google/protobuf/extension_set.h>\n");
- if (HasMapFields(file_)) {
- printer->Print(
- "#include <google/protobuf/map.h>\n");
- if (HasDescriptorMethods(file_)) {
- printer->Print(
- "#include <google/protobuf/map_field_inl.h>\n");
- } else {
- printer->Print(
- "#include <google/protobuf/map_field_lite.h>\n");
- }
- }
-
- if (HasEnumDefinitions(file_)) {
- if (HasDescriptorMethods(file_)) {
- printer->Print(
- "#include <google/protobuf/generated_enum_reflection.h>\n");
- } else {
- printer->Print(
- "#include <google/protobuf/generated_enum_util.h>\n");
- }
- }
-
- if (HasGenericServices(file_)) {
- printer->Print(
- "#include <google/protobuf/service.h>\n");
- }
-
- if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
- printer->Print(
- "#include <google/protobuf/unknown_field_set.h>\n");
- }
-
-
- set<string> public_import_names;
- for (int i = 0; i < file_->public_dependency_count(); i++) {
- public_import_names.insert(file_->public_dependency(i)->name());
- }
-
- for (int i = 0; i < file_->dependency_count(); i++) {
- const string& name = file_->dependency(i)->name();
- bool public_import = (public_import_names.count(name) != 0);
+ GenerateTopHeaderGuard(printer);
-
- printer->Print(
- "#include \"$dependency$.pb.h\"$iwyu$\n",
- "dependency", StripProto(name),
- "iwyu", (public_import) ? " // IWYU pragma: export" : "");
- }
+ GenerateLibraryIncludes(printer);
+ GenerateDependencyIncludes(printer);
printer->Print(
"// @@protoc_insertion_point(includes)\n");
@@ -210,132 +107,44 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// Open namespace.
GenerateNamespaceOpeners(printer);
- // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
- // functions, so that we can declare them to be friends of each class.
- printer->Print(
- "\n"
- "// Internal implementation detail -- do not call these.\n"
- "void $dllexport_decl$$adddescriptorsname$();\n",
- "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
- "dllexport_decl",
- options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
-
- printer->Print(
- // Note that we don't put dllexport_decl on these because they are only
- // called by the .pb.cc file in which they are defined.
- "void $assigndescriptorsname$();\n"
- "void $shutdownfilename$();\n"
- "\n",
- "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
- "shutdownfilename", GlobalShutdownFileName(file_->name()));
-
- // Generate forward declarations of classes.
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateForwardDeclaration(printer);
- }
+ GenerateGlobalStateFunctionDeclarations(printer);
+ GenerateMessageForwardDeclarations(printer);
printer->Print("\n");
- // Generate enum definitions.
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateEnumDefinitions(printer);
- }
- for (int i = 0; i < file_->enum_type_count(); i++) {
- enum_generators_[i]->GenerateDefinition(printer);
- }
+ GenerateEnumDefinitions(printer);
printer->Print(kThickSeparator);
printer->Print("\n");
- // Generate class definitions.
- for (int i = 0; i < file_->message_type_count(); i++) {
- if (i > 0) {
- printer->Print("\n");
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- message_generators_[i]->GenerateClassDefinition(printer);
- }
+ GenerateMessageDefinitions(printer);
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
- if (HasGenericServices(file_)) {
- // Generate service definitions.
- for (int i = 0; i < file_->service_count(); i++) {
- if (i > 0) {
- printer->Print("\n");
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- service_generators_[i]->GenerateDeclarations(printer);
- }
-
- printer->Print("\n");
- printer->Print(kThickSeparator);
- printer->Print("\n");
- }
+ GenerateServiceDefinitions(printer);
- // Declare extension identifiers.
- for (int i = 0; i < file_->extension_count(); i++) {
- extension_generators_[i]->GenerateDeclaration(printer);
- }
+ GenerateExtensionIdentifiers(printer);
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
- printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
- // Generate class inline methods.
- for (int i = 0; i < file_->message_type_count(); i++) {
- if (i > 0) {
- printer->Print(kThinSeparator);
- printer->Print("\n");
- }
- message_generators_[i]->GenerateInlineMethods(printer,
- /* is_inline = */ true);
- }
- printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
-
- printer->Print(
- "\n"
- "// @@protoc_insertion_point(namespace_scope)\n");
+ GenerateInlineFunctionDefinitions(printer);
// Close up namespace.
GenerateNamespaceClosers(printer);
- // Emit GetEnumDescriptor specializations into google::protobuf namespace:
- if (HasEnumDefinitions(file_)) {
- // The SWIG conditional is to avoid a null-pointer dereference
- // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
- // namespace X { void Y<Z::W>(); }
- // which appears in GetEnumDescriptor() specializations.
- printer->Print(
- "\n"
- "#ifndef SWIG\n"
- "namespace google {\nnamespace protobuf {\n"
- "\n");
- for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
- }
- for (int i = 0; i < file_->enum_type_count(); i++) {
- enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
- }
- printer->Print(
- "\n"
- "} // namespace protobuf\n} // namespace google\n"
- "#endif // SWIG\n");
- }
+ // We need to specialize some templates in the ::google::protobuf namespace:
+ GenerateProto2NamespaceEnumSpecializations(printer);
printer->Print(
"\n"
"// @@protoc_insertion_point(global_scope)\n"
"\n");
- printer->Print(
- "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
- "filename_identifier", filename_identifier);
+ GenerateBottomHeaderGuard(printer);
}
void FileGenerator::GenerateSource(io::Printer* printer) {
@@ -707,6 +516,294 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
}
}
+void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) {
+ string filename_identifier = FilenameIdentifier(file_->name());
+ // Generate top of header.
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n"
+ "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "\n"
+ "#include <string>\n"
+ "\n",
+ "filename", file_->name(),
+ "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) {
+ string filename_identifier = FilenameIdentifier(file_->name());
+ printer->Print(
+ "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
+ "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+
+ printer->Print(
+ "#include <google/protobuf/stubs/common.h>\n"
+ "\n");
+
+ // Verify the protobuf library header version is compatible with the protoc
+ // version before going any further.
+ printer->Print(
+ "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
+ "#error This file was generated by a newer version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please update\n"
+ "#error your headers.\n"
+ "#endif\n"
+ "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
+ "#error This file was generated by an older version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please\n"
+ "#error regenerate this file with a newer version of protoc.\n"
+ "#endif\n"
+ "\n",
+ "min_header_version",
+ SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
+ "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
+
+ // OK, it's now safe to #include other files.
+ printer->Print(
+ "#include <google/protobuf/arena.h>\n"
+ "#include <google/protobuf/arenastring.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n");
+ if (UseUnknownFieldSet(file_)) {
+ printer->Print(
+ "#include <google/protobuf/metadata.h>\n");
+ }
+ if (file_->message_type_count() > 0) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/message.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/message_lite.h>\n");
+ }
+ }
+ printer->Print(
+ "#include <google/protobuf/repeated_field.h>\n"
+ "#include <google/protobuf/extension_set.h>\n");
+ if (HasMapFields(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map.h>\n");
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map_field_inl.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/map_field_lite.h>\n");
+ }
+ }
+
+ if (HasEnumDefinitions(file_)) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_reflection.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_util.h>\n");
+ }
+ }
+
+ if (HasGenericServices(file_)) {
+ printer->Print(
+ "#include <google/protobuf/service.h>\n");
+ }
+
+ if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/unknown_field_set.h>\n");
+ }
+
+
+ if (IsAnyMessage(file_)) {
+ printer->Print(
+ "#include \"google/protobuf/any.h\"\n");
+ }
+}
+
+void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
+ set<string> public_import_names;
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ public_import_names.insert(file_->public_dependency(i)->name());
+ }
+
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ const string& name = file_->dependency(i)->name();
+ bool public_import = (public_import_names.count(name) != 0);
+
+
+ printer->Print(
+ "#include \"$dependency$.pb.h\"$iwyu$\n",
+ "dependency", StripProto(name),
+ "iwyu", (public_import) ? " // IWYU pragma: export" : "");
+ }
+}
+
+void FileGenerator::GenerateGlobalStateFunctionDeclarations(
+ io::Printer* printer) {
+ // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+ // functions, so that we can declare them to be friends of each class.
+ printer->Print(
+ "\n"
+ "// Internal implementation detail -- do not call these.\n"
+ "void $dllexport_decl$$adddescriptorsname$();\n",
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
+ "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+
+ printer->Print(
+ // Note that we don't put dllexport_decl on these because they are only
+ // called by the .pb.cc file in which they are defined.
+ "void $assigndescriptorsname$();\n"
+ "void $shutdownfilename$();\n"
+ "\n",
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
+ "shutdownfilename", GlobalShutdownFileName(file_->name()));
+}
+
+void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
+ // Generate forward declarations of classes.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateMessageForwardDeclaration(printer);
+ }
+}
+
+void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
+ // Generate class definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateClassDefinition(printer);
+ }
+}
+
+void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
+ // Generate enum definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateEnumDefinitions(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDefinition(printer);
+ }
+}
+
+void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
+ if (HasGenericServices(file_)) {
+ // Generate service definitions.
+ for (int i = 0; i < file_->service_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ service_generators_[i]->GenerateDeclarations(printer);
+ }
+
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ }
+}
+
+void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
+ // Declare extension identifiers.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateDeclaration(printer);
+ }
+}
+
+void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
+ // An aside about inline functions in .proto.h mode:
+ //
+ // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally
+ // moving much of the inline functions to the .pb.cc file, which can be a
+ // significant performance benefit for compilation time, at the expense
+ // of non-inline function calls.
+ //
+ // However, in .proto.h mode, the definition of the internal dependent
+ // base class must remain in the header, and can never be out-lined. The
+ // dependent base class also needs access to has-bit manipuation
+ // functions, so the has-bit functions must be unconditionally inlined in
+ // proto_h mode.
+ //
+ // This gives us three flavors of functions:
+ //
+ // 1. Functions on the message not used by the internal dependent base
+ // class: in .proto.h mode, only some functions are defined on the
+ // message class; others are defined on the dependent base class.
+ // These are guarded and can be out-lined. These are generated by
+ // GenerateInlineMethods, and include has_* bit functions in
+ // non-proto_h mode.
+ //
+ // 2. Functions on the internal dependent base class: these functions
+ // are dependent on a template parameter, so they always need to
+ // remain in the header.
+ //
+ // 3. Functions on the message that are used by the dependent base: the
+ // dependent base class down casts itself to the message
+ // implementation class to access these functions (the has_* bit
+ // manipulation functions). Unlike #1, these functions must
+ // unconditionally remain in the header. These are emitted by
+ // GenerateDependentInlineMethods, even though they are not actually
+ // dependent.
+
+ printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // Generate class inline methods.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateInlineMethods(printer,
+ /* is_inline = */ true);
+ }
+ printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ // Methods of the dependent base class must always be inline in the header.
+ message_generators_[i]->GenerateDependentInlineMethods(printer);
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n");
+}
+
+void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
+ io::Printer* printer) {
+ // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+ if (HasEnumDefinitions(file_)) {
+ // The SWIG conditional is to avoid a null-pointer dereference
+ // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
+ // namespace X { void Y<Z::W>(); }
+ // which appears in GetEnumDescriptor() specializations.
+ printer->Print(
+ "\n"
+ "#ifndef SWIG\n"
+ "namespace google {\nnamespace protobuf {\n"
+ "\n");
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+ }
+ printer->Print(
+ "\n"
+ "} // namespace protobuf\n} // namespace google\n"
+ "#endif // SWIG\n");
+ }
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 0e06547d..e68f67bb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -80,6 +80,35 @@ class FileGenerator {
void GenerateNamespaceOpeners(io::Printer* printer);
void GenerateNamespaceClosers(io::Printer* printer);
+ // Generates top or bottom of a header file.
+ void GenerateTopHeaderGuard(io::Printer* printer);
+ void GenerateBottomHeaderGuard(io::Printer* printer);
+
+ // Generates #include directives.
+ void GenerateLibraryIncludes(io::Printer* printer);
+ void GenerateDependencyIncludes(io::Printer* printer);
+
+ // Generates a couple of different pieces before definitions:
+ void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
+
+ // Generates types for classes.
+ void GenerateMessageForwardDeclarations(io::Printer* printer);
+ void GenerateMessageDefinitions(io::Printer* printer);
+
+ // Generates enum definitions.
+ void GenerateEnumDefinitions(io::Printer* printer);
+
+ // Generates generic service definitions.
+ void GenerateServiceDefinitions(io::Printer* printer);
+
+ // Generates extension identifiers.
+ void GenerateExtensionIdentifiers(io::Printer* printer);
+
+ // Generates inline function defintions.
+ void GenerateInlineFunctionDefinitions(io::Printer* printer);
+
+ void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
+
const FileDescriptor* file_;
google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index c999b93f..99416372 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -82,6 +82,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// }
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
// __declspec(dllimport) depending on what is being compiled.
+ //
Options file_options;
for (int i = 0; i < options.size(); i++) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 4e7155c3..0f3688d0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -51,6 +51,9 @@ namespace cpp {
namespace {
+static const char kAnyMessageName[] = "Any";
+static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+
string DotsToUnderscores(const string& name) {
return StringReplace(name, ".", "_", true);
}
@@ -162,6 +165,10 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
}
+string DependentBaseClassTemplateName(const Descriptor* descriptor) {
+ return ClassName(descriptor, false) + "_InternalBase";
+}
+
string SuperClassName(const Descriptor* descriptor) {
return HasDescriptorMethods(descriptor->file()) ?
"::google::protobuf::Message" : "::google::protobuf::MessageLite";
@@ -200,6 +207,47 @@ string FieldConstantName(const FieldDescriptor *field) {
return result;
}
+bool IsFieldDependent(const FieldDescriptor* field) {
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ return false;
+ }
+ if (field->containing_oneof() != NULL) {
+ // Oneof fields will always be dependent.
+ //
+ // This is a unique case for field codegen. Field generators are
+ // responsible for generating all the field-specific accessor
+ // functions, except for the clear_*() function; instead, field
+ // generators produce inline clearing code.
+ //
+ // For non-oneof fields, the Message class uses the inline clearing
+ // code to define the field's clear_*() function, as well as in the
+ // destructor. For oneof fields, the Message class generates a much
+ // more complicated clear_*() function, which clears only the oneof
+ // member that is set, in addition to clearing methods for each of the
+ // oneof members individually.
+ //
+ // Since oneofs do not have their own generator class, the Message code
+ // generation logic would be significantly complicated in order to
+ // split dependent and non-dependent manipulation logic based on
+ // whether the oneof truly needs to be dependent; so, for oneof fields,
+ // we just assume it (and its constituents) should be manipulated by a
+ // dependent base class function.
+ //
+ // This is less precise than how dependent message-typed fields are
+ // handled, but the cost is limited to only the generated code for the
+ // oneof field, which seems like an acceptable tradeoff.
+ return true;
+ }
+ if (field->file() == field->message_type()->file()) {
+ return false;
+ }
+ return true;
+}
+
+string DependentTypeName(const FieldDescriptor* field) {
+ return "InternalBase_" + field->name() + "_T";
+}
+
string FieldMessageTypeName(const FieldDescriptor* field) {
// Note: The Google-internal version of Protocol Buffers uses this function
// as a hook point for hacks to support legacy code.
@@ -360,7 +408,7 @@ string FilenameIdentifier(const string& filename) {
} else {
// Not alphanumeric. To avoid any possibility of name conflicts we
// use the hex code for the character.
- StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
+ StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
}
}
return result;
@@ -521,6 +569,15 @@ FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
}
+bool IsAnyMessage(const FileDescriptor* descriptor) {
+ return descriptor->name() == kAnyProtoFile;
+}
+
+bool IsAnyMessage(const Descriptor* descriptor) {
+ return descriptor->name() == kAnyMessageName &&
+ descriptor->file()->name() == kAnyProtoFile;
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 284fa2c1..4bbf8303 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -66,6 +66,10 @@ extern const char kThinSeparator[];
string ClassName(const Descriptor* descriptor, bool qualified);
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
+// Name of the CRTP class template (for use with proto_h).
+// This is a class name, like "ProtoName_InternalBase".
+string DependentBaseClassTemplateName(const Descriptor* descriptor);
+
string SuperClassName(const Descriptor* descriptor);
// Get the (unqualified) name that should be used for this field in C++ code.
@@ -88,6 +92,20 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) {
field->extension_scope() : field->containing_type();
}
+// Returns true if the given 'field_descriptor' has a message type that is
+// a dependency of the file where the field is defined (i.e., the field
+// type is defined in a different file than the message holding the field).
+//
+// This only applies to Message-typed fields. Enum-typed fields may refer
+// to an enum in a dependency; however, enums are specified and
+// forward-declared with an enum-base, so the definition is not required to
+// manipulate the field value.
+bool IsFieldDependent(const FieldDescriptor* field_descriptor);
+
+// Returns the name that should be used for forcing dependent lookup from a
+// dependent base class.
+string DependentTypeName(const FieldDescriptor* field);
+
// Returns the fully-qualified type name field->message_type(). Usually this
// is just ClassName(field->message_type(), true);
string FieldMessageTypeName(const FieldDescriptor* field);
@@ -242,6 +260,9 @@ inline bool SupportsArenas(const FieldDescriptor* field) {
return SupportsArenas(field->file());
}
+bool IsAnyMessage(const FileDescriptor* descriptor);
+bool IsAnyMessage(const Descriptor* descriptor);
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 8c38db2b..0ff0d27c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -244,7 +244,8 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
// If entry is allocated by arena, its desctructor should be avoided.
if (SupportsArenas(descriptor_)) {
@@ -277,7 +278,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
// If entry is allocated by arena, its desctructor should be avoided.
if (SupportsArenas(descriptor_)) {
@@ -312,7 +314,8 @@ GenerateByteSize(io::Printer* printer) const {
"{\n"
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
- " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it) {\n");
// If entry is allocated by arena, its desctructor should be avoided.
if (SupportsArenas(descriptor_)) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 98929b1e..212fe2e1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -64,10 +64,15 @@ using internal::WireFormatLite;
namespace {
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
- // Print the field's proto-syntax definition as a comment. We don't want to
- // print group bodies so we cut off after the first line.
- string def = field->DebugString();
+template <class T>
+void PrintFieldComment(io::Printer* printer, const T* field) {
+ // Print the field's (or oneof's) proto-syntax definition as a comment.
+ // We don't want to print group bodies so we cut off after the first
+ // line.
+ DebugStringOptions options;
+ options.elide_group_body = true;
+ options.elide_oneof_body = true;
+ string def = field->DebugStringWithOptions(options);
printer->Print("// $def$\n",
"def", def.substr(0, def.find_first_of('\n')));
}
@@ -280,6 +285,10 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
}
}
+string MessageTypeProtoName(const FieldDescriptor* field) {
+ return field->message_type()->full_name();
+}
+
// Emits an if-statement with a condition that evaluates to true if |field| is
// considered non-default (will be sent over the wire), for message types
// without true field presence. Should only be called if
@@ -379,7 +388,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
enum_generators_(
new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
extension_generators_(new google::protobuf::scoped_ptr<
- ExtensionGenerator>[descriptor->extension_count()]) {
+ ExtensionGenerator>[descriptor->extension_count()]),
+ use_dependent_base_(false) {
for (int i = 0; i < descriptor->nested_type_count(); i++) {
nested_generators_[i].reset(
@@ -401,13 +411,16 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
if (descriptor->field(i)->is_required()) {
++num_required_fields_;
}
+ if (options.proto_h && IsFieldDependent(descriptor->field(i))) {
+ use_dependent_base_ = true;
+ }
}
}
MessageGenerator::~MessageGenerator() {}
void MessageGenerator::
-GenerateForwardDeclaration(io::Printer* printer) {
+GenerateMessageForwardDeclaration(io::Printer* printer) {
printer->Print("class $classname$;\n",
"classname", classname_);
@@ -416,7 +429,17 @@ GenerateForwardDeclaration(io::Printer* printer) {
// message cannot be a top level class, we just need to avoid calling
// GenerateForwardDeclaration here.
if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
- nested_generators_[i]->GenerateForwardDeclaration(printer);
+ nested_generators_[i]->GenerateMessageForwardDeclaration(printer);
+ }
+}
+
+void MessageGenerator::
+GenerateEnumForwardDeclaration(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateEnumForwardDeclaration(printer);
+ }
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateForwardDeclaration(printer);
}
}
@@ -442,6 +465,35 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
}
void MessageGenerator::
+GenerateDependentFieldAccessorDeclarations(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ // If the message is dependent, the inline clear_*() method will need
+ // to delete the message type, so it must be in the dependent base
+ // class. (See also GenerateFieldAccessorDeclarations.)
+ printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+ }
+ // Generate type-specific accessor declarations.
+ field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
+ printer->Print("\n");
+ }
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+ PrintFieldComment(printer, oneof);
+ printer->Print(
+ "void clear_$oneof_name$();\n",
+ "oneof_name", oneof->name());
+ }
+}
+
+void MessageGenerator::
GenerateFieldAccessorDeclarations(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
@@ -452,6 +504,19 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
SetCommonFieldVariables(field, &vars, options_);
vars["constant_name"] = FieldConstantName(field);
+ bool dependent_field = use_dependent_base_ && IsFieldDependent(field);
+ if (dependent_field) {
+ // If this field is dependent, the dependent base class determines
+ // the message type from the derived class (which is a template
+ // parameter). This typedef is for that:
+ printer->Print(
+ "private:\n"
+ "typedef $field_type$ $dependent_type$;\n"
+ "public:\n",
+ "field_type", FieldMessageTypeName(field),
+ "dependent_type", DependentTypeName(field));
+ }
+
if (field->is_repeated()) {
printer->Print(vars, "int $name$_size() const$deprecation$;\n");
} else if (HasHasMethod(field)) {
@@ -463,7 +528,11 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
"public:\n");
}
- printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+ if (!dependent_field) {
+ // If this field is dependent, then its clear_() method is in the
+ // depenent base class. (See also GenerateDependentAccessorDeclarations.)
+ printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+ }
printer->Print(vars, "static const int $constant_name$ = $number$;\n");
// Generate type-specific accessor declarations.
@@ -490,6 +559,188 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
}
void MessageGenerator::
+GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
+ if (!use_dependent_base_) return;
+
+ printer->Print("// $classname$\n\n", "classname",
+ DependentBaseClassTemplateName(descriptor_));
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ // These functions are not really dependent: they are part of the
+ // (non-dependent) derived class. However, they need to live outside
+ // any #ifdef guards, so we treat them as if they were dependent.
+ //
+ // See the comment in FileGenerator::GenerateInlineFunctionDefinitions
+ // for a more complete explanation.
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+ vars["inline"] = "inline ";
+ if (field->containing_oneof()) {
+ vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
+ vars["oneof_name"] = field->containing_oneof()->name();
+ vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
+ GenerateOneofMemberHasBits(field, vars, printer);
+ } else if (!field->is_repeated()) {
+ // There will be no header guard, so this always has to be inline.
+ GenerateSingularFieldHasBits(field, vars, printer);
+ }
+ // vars needed for clear_(), which is in the dependent base:
+ // (See also GenerateDependentFieldAccessorDeclarations.)
+ vars["tmpl"] = "template<class T>\n";
+ vars["dependent_classname"] =
+ DependentBaseClassTemplateName(descriptor_) + "<T>";
+ vars["this_message"] = "reinterpret_cast<T*>(this)->";
+ vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+ GenerateFieldClear(field, vars, printer);
+ }
+
+ // Generate type-specific accessors.
+ field_generators_.get(field)
+ .GenerateDependentInlineAccessorDefinitions(printer);
+
+ printer->Print("\n");
+ }
+
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs
+ // Similar to other has-bits, these must always be in the header if we
+ // are using a dependent base class.
+ GenerateOneofHasBits(printer, true /* is_inline */);
+}
+
+void MessageGenerator::
+GenerateSingularFieldHasBits(const FieldDescriptor* field,
+ map<string, string> vars,
+ io::Printer* printer) {
+ if (HasFieldPresence(descriptor_->file())) {
+ // N.B.: without field presence, we do not use has-bits or generate
+ // has_$name$() methods.
+ vars["has_array_index"] = SimpleItoa(field->index() / 32);
+ vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32),
+ strings::Hex::ZERO_PAD_8));
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::set_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::clear_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
+ "}\n");
+ } else {
+ // Message fields have a has_$name$() method.
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ bool is_lazy = false;
+ if (is_lazy) {
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return !$name$_.IsCleared();\n"
+ "}\n");
+ } else {
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return !_is_default_instance_ && $name$_ != NULL;\n"
+ "}\n");
+ }
+ }
+ }
+}
+
+void MessageGenerator::
+GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ map<string, string> vars;
+ vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ vars["cap_oneof_name"] =
+ ToUpper(descriptor_->oneof_decl(i)->name());
+ vars["classname"] = classname_;
+ vars["inline"] = (is_inline ? "inline " : "");
+ printer->Print(
+ vars,
+ "$inline$"
+ "bool $classname$::has_$oneof_name$() const {\n"
+ " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
+ "}\n"
+ "$inline$"
+ "void $classname$::clear_has_$oneof_name$() {\n"
+ " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
+ "}\n");
+ }
+}
+
+void MessageGenerator::
+GenerateOneofMemberHasBits(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer) {
+ // Singular field in a oneof
+ // N.B.: Without field presence, we do not use has-bits or generate
+ // has_$name$() methods, but oneofs still have set_has_$name$().
+ // Oneofs also have has_$name$() but only as a private helper
+ // method, so that generated code is slightly cleaner (vs. comparing
+ // _oneof_case_[index] against a constant everywhere).
+ printer->Print(vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return $oneof_name$_case() == k$field_name$;\n"
+ "}\n");
+ printer->Print(vars,
+ "$inline$"
+ "void $classname$::set_has_$name$() {\n"
+ " _oneof_case_[$oneof_index$] = k$field_name$;\n"
+ "}\n");
+}
+
+void MessageGenerator::
+GenerateFieldClear(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer) {
+ // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and
+ // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is
+ // set by the Generate*Definitions functions.)
+ printer->Print(vars,
+ "$tmpl$"
+ "$inline$"
+ "void $dependent_classname$::clear_$name$() {\n");
+
+ printer->Indent();
+
+ if (field->containing_oneof()) {
+ // Clear this field only if it is the active field in this oneof,
+ // otherwise ignore
+ printer->Print(vars,
+ "if ($this_message$has_$name$()) {\n");
+ printer->Indent();
+ field_generators_.get(field).GenerateClearingCode(printer);
+ printer->Print(vars,
+ "$this_message$clear_has_$oneof_name$();\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ if (HasFieldPresence(descriptor_->file())) {
+ if (!field->is_repeated()) {
+ printer->Print(vars,
+ "$this_message$clear_has_$name$();\n");
+ }
+ }
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
printer->Print("// $classname$\n\n", "classname", classname_);
@@ -500,101 +751,37 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
map<string, string> vars;
SetCommonFieldVariables(field, &vars, options_);
- vars["inline"] = is_inline ? "inline" : "";
+ vars["inline"] = is_inline ? "inline " : "";
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
printer->Print(vars,
- "$inline$ int $classname$::$name$_size() const {\n"
+ "$inline$"
+ "int $classname$::$name$_size() const {\n"
" return $name$_.size();\n"
"}\n");
} else if (field->containing_oneof()) {
- // Singular field in a oneof
- // N.B.: Without field presence, we do not use has-bits or generate
- // has_$name$() methods, but oneofs still have set_has_$name$().
- // Oneofs also have has_$name$() but only as a private helper
- // method, so that generated code is slightly cleaner (vs. comparing
- // _oneof_case_[index] against a constant everywhere).
vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
vars["oneof_name"] = field->containing_oneof()->name();
vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
- printer->Print(vars,
- "$inline$ bool $classname$::has_$name$() const {\n"
- " return $oneof_name$_case() == k$field_name$;\n"
- "}\n");
- printer->Print(vars,
- "$inline$ void $classname$::set_has_$name$() {\n"
- " _oneof_case_[$oneof_index$] = k$field_name$;\n"
- "}\n");
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ GenerateOneofMemberHasBits(field, vars, printer);
+ }
} else {
// Singular field.
- if (HasFieldPresence(descriptor_->file())) {
- // N.B.: without field presence, we do not use has-bits or generate
- // has_$name$() methods.
- char buffer[kFastToBufferSize];
- vars["has_array_index"] = SimpleItoa(field->index() / 32);
- vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
- buffer);
- printer->Print(vars,
- "$inline$ bool $classname$::has_$name$() const {\n"
- " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
- "}\n"
- "$inline$ void $classname$::set_has_$name$() {\n"
- " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
- "}\n"
- "$inline$ void $classname$::clear_has_$name$() {\n"
- " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
- "}\n"
- );
- } else {
- // Message fields have a has_$name$() method.
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- bool is_lazy = false;
- if (is_lazy) {
- printer->Print(vars,
- "$inline$ bool $classname$::has_$name$() const {\n"
- " return !$name$_.IsCleared();\n"
- "}\n");
- } else {
- printer->Print(vars,
- "$inline$ bool $classname$::has_$name$() const {\n"
- " return !_is_default_instance_ && $name$_ != NULL;\n"
- "}\n");
- }
- }
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ GenerateSingularFieldHasBits(field, vars, printer);
}
}
- // Generate clear_$name$()
- printer->Print(vars,
- "$inline$ void $classname$::clear_$name$() {\n");
-
- printer->Indent();
-
- if (field->containing_oneof()) {
- // Clear this field only if it is the active field in this oneof,
- // otherwise ignore
- printer->Print(vars,
- "if (has_$name$()) {\n");
- printer->Indent();
- field_generators_.get(field).GenerateClearingCode(printer);
- printer->Print(vars,
- "clear_has_$oneof_name$();\n");
- printer->Outdent();
- printer->Print("}\n");
- } else {
- field_generators_.get(field).GenerateClearingCode(printer);
- if (HasFieldPresence(descriptor_->file())) {
- if (!field->is_repeated()) {
- printer->Print(vars,
- "clear_has_$name$();\n");
- }
- }
+ if (!use_dependent_base_ || !IsFieldDependent(field)) {
+ vars["tmpl"] = "";
+ vars["dependent_classname"] = vars["classname"];
+ vars["this_message"] = "";
+ vars["this_const_message"] = "";
+ GenerateFieldClear(field, vars, printer);
}
- printer->Outdent();
- printer->Print("}\n");
-
// Generate type-specific accessors.
field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
is_inline);
@@ -602,23 +789,11 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
printer->Print("\n");
}
- // Generate has_$name$() and clear_has_$name$() functions for oneofs
- for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- map<string, string> vars;
- vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
- vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
- vars["cap_oneof_name"] =
- ToUpper(descriptor_->oneof_decl(i)->name());
- vars["classname"] = classname_;
- vars["inline"] = is_inline ? "inline" : "";
- printer->Print(
- vars,
- "$inline$ bool $classname$::has_$oneof_name$() const {\n"
- " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
- "}\n"
- "$inline$ void $classname$::clear_has_$oneof_name$() {\n"
- " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
- "}\n");
+ if (!use_dependent_base_) {
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs
+ // If we aren't using a dependent base, they can be with the other functions
+ // that are #ifdef-guarded.
+ GenerateOneofHasBits(printer, is_inline);
}
}
@@ -648,6 +823,34 @@ static bool CanClearByZeroing(const FieldDescriptor* field) {
}
void MessageGenerator::
+GenerateDependentBaseClassDefinition(io::Printer* printer) {
+ if (!use_dependent_base_) {
+ return;
+ }
+
+ map<string, string> vars;
+ vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+ vars["superclass"] = SuperClassName(descriptor_);
+
+ printer->Print(vars,
+ "template <class T>\n"
+ "class $classname$ : public $superclass$ {\n"
+ " public:\n");
+ printer->Indent();
+
+ printer->Print(vars,
+ "$classname$() {}\n"
+ "virtual ~$classname$() {}\n"
+ "\n");
+
+ // Generate dependent accessor methods for all fields.
+ GenerateDependentFieldAccessorDeclarations(printer);
+
+ printer->Outdent();
+ printer->Print("};\n");
+}
+
+void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// map entry message doesn't need class definition. Since map entry message
@@ -660,6 +863,11 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print("\n");
}
+ if (use_dependent_base_) {
+ GenerateDependentBaseClassDefinition(printer);
+ printer->Print("\n");
+ }
+
map<string, string> vars;
vars["classname"] = classname_;
vars["field_count"] = SimpleItoa(descriptor_->field_count());
@@ -669,11 +877,18 @@ GenerateClassDefinition(io::Printer* printer) {
} else {
vars["dllexport"] = options_.dllexport_decl + " ";
}
- vars["superclass"] = SuperClassName(descriptor_);
-
+ if (use_dependent_base_) {
+ vars["superclass"] =
+ DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+ } else {
+ vars["superclass"] = SuperClassName(descriptor_);
+ }
printer->Print(vars,
- "class $dllexport$$classname$ : public $superclass$ {\n"
- " public:\n");
+ "class $dllexport$$classname$ : public $superclass$ {\n");
+ if (use_dependent_base_) {
+ printer->Print(vars, " friend class $superclass$;\n");
+ }
+ printer->Print(" public:\n");
printer->Indent();
printer->Print(vars,
@@ -782,6 +997,19 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(vars,
"void UnsafeArenaSwap($classname$* other);\n");
}
+
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(vars,
+ "// implements Any -----------------------------------------------\n"
+ "\n"
+ "void PackFrom(const ::google::protobuf::Message& message);\n"
+ "bool UnpackTo(::google::protobuf::Message* message) const;\n"
+ "template<typename T> bool Is() const {\n"
+ " return _any_metadata_.Is<T>();\n"
+ "}\n"
+ "\n");
+ }
+
printer->Print(vars,
"void Swap($classname$* other);\n"
"\n"
@@ -973,11 +1201,18 @@ GenerateClassDefinition(io::Printer* printer) {
// Generate oneof function declarations
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print(
- "inline bool has_$oneof_name$() const;\n"
- "void clear_$oneof_name$();\n"
- "inline void clear_has_$oneof_name$();\n\n",
- "oneof_name", descriptor_->oneof_decl(i)->name());
+ if (use_dependent_base_) {
+ printer->Print(
+ "inline bool has_$oneof_name$() const;\n"
+ "inline void clear_has_$oneof_name$();\n\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ } else {
+ printer->Print(
+ "inline bool has_$oneof_name$() const;\n"
+ "void clear_$oneof_name$();\n"
+ "inline void clear_has_$oneof_name$();\n\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
}
if (HasGeneratedMethods(descriptor_->file()) &&
@@ -1139,6 +1374,12 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+ // Generate _any_metadata_ for the Any type.
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(vars,
+ "::google::protobuf::internal::AnyMetadata _any_metadata_;\n");
+ }
+
// Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
// friends so that they can access private static variables like
// default_instance_ and reflection_.
@@ -1172,6 +1413,21 @@ GenerateClassDefinition(io::Printer* printer) {
}
void MessageGenerator::
+GenerateDependentInlineMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need inline methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateInlineMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+ nested_generators_[i]->GenerateDependentInlineMethods(printer);
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+
+ GenerateDependentFieldAccessorDefinitions(printer);
+}
+
+void MessageGenerator::
GenerateInlineMethods(io::Printer* printer, bool is_inline) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// map entry message doesn't need inline methods. Since map entry message
@@ -1196,7 +1452,8 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) {
vars["inline"] = is_inline ? "inline " : "";
printer->Print(
vars,
- "$inline$$class_name$::$camel_oneof_name$Case $class_name$::"
+ "$inline$"
+ "$class_name$::$camel_oneof_name$Case $class_name$::"
"$oneof_name$_case() const {\n"
" return $class_name$::$camel_oneof_name$Case("
"_oneof_case_[$oneof_index$]);\n"
@@ -1494,6 +1751,19 @@ GenerateShutdownCode(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(
+ "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
+ " _any_metadata_.PackFrom(message);\n"
+ "}\n"
+ "\n"
+ "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
+ " return _any_metadata_.UnpackTo(message);\n"
+ "}\n"
+ "\n",
+ "classname", classname_);
+ }
+
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
enum_generators_[i]->GenerateMethods(printer);
}
@@ -1767,7 +2037,7 @@ GenerateArenaDestructorCode(io::Printer* printer) {
if (need_registration) {
printer->Print(
"inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
- " if (arena != NULL) {"
+ " if (arena != NULL) {\n"
" arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
" }\n"
"}\n",
@@ -1782,18 +2052,23 @@ GenerateArenaDestructorCode(io::Printer* printer) {
void MessageGenerator::
GenerateStructors(io::Printer* printer) {
- string superclass = SuperClassName(descriptor_);
- string initializer_with_arena;
- if (UseUnknownFieldSet(descriptor_->file())) {
- initializer_with_arena = "_internal_metadata_(arena)";
+ string superclass;
+ if (use_dependent_base_) {
+ superclass =
+ DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
} else {
- initializer_with_arena = "_arena_ptr_(arena)";
+ superclass = SuperClassName(descriptor_);
}
+ string initializer_with_arena = superclass + "()";
+
if (descriptor_->extension_range_count() > 0) {
- initializer_with_arena = string("\n _extensions_(arena)") +
- (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena;
+ initializer_with_arena += ",\n _extensions_(arena)";
+ }
+
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ initializer_with_arena += ",\n _internal_metadata_(arena)";
} else {
- initializer_with_arena = "\n " + initializer_with_arena;
+ initializer_with_arena += ",\n _arena_ptr_(arena)";
}
// Initialize member variables with arena constructor.
@@ -1804,16 +2079,21 @@ GenerateStructors(io::Printer* printer) {
FieldName(descriptor_->field(i)) + string("_(arena)");
}
}
- initializer_with_arena = superclass + "()" +
- (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena;
+
+ if (IsAnyMessage(descriptor_)) {
+ initializer_with_arena += ",\n _any_metadata_(&type_url, &value_)";
+ }
string initializer_null;
initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
- ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
+ ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)");
+ if (IsAnyMessage(descriptor_)) {
+ initializer_null += ", _any_metadata_(&type_url_, &value_)";
+ }
printer->Print(
"$classname$::$classname$()\n"
- " : $superclass$() $initializer$ {\n"
+ " : $superclass$()$initializer$ {\n"
" SharedCtor();\n"
" // @@protoc_insertion_point(constructor:$full_name$)\n"
"}\n",
@@ -1894,10 +2174,14 @@ GenerateStructors(io::Printer* printer) {
"full_name", descriptor_->full_name());
if (UseUnknownFieldSet(descriptor_->file())) {
printer->Print(
- ",\n _internal_metadata_(NULL) {\n");
+ ",\n _internal_metadata_(NULL)");
} else if (!UseUnknownFieldSet(descriptor_->file())) {
- printer->Print(",\n _arena_ptr_(NULL) {\n");
+ printer->Print(",\n _arena_ptr_(NULL)");
}
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(",\n _any_metadata_(&type_url_, &value_)");
+ }
+ printer->Print(" {\n");
printer->Print(
" SharedCtor();\n"
" MergeFrom(from);\n"
@@ -2124,7 +2408,11 @@ GenerateClear(io::Printer* printer) {
have_enclosing_if = true;
}
- field_generators_.get(field).GenerateClearingCode(printer);
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ printer->Print("clear_$name$();\n", "name", fieldname);
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
if (have_enclosing_if) {
printer->Outdent();
@@ -2147,7 +2435,11 @@ GenerateClear(io::Printer* printer) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
- field_generators_.get(field).GenerateClearingCode(printer);
+ if (use_dependent_base_ && IsFieldDependent(field)) {
+ printer->Print("clear_$name$();\n", "name", FieldName(field));
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
}
}
@@ -2184,19 +2476,38 @@ void MessageGenerator::
GenerateOneofClear(io::Printer* printer) {
// Generated function clears the active field and union case (e.g. foo_case_).
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
- printer->Print(
- "void $classname$::clear_$oneofname$() {\n",
- "classname", classname_,
- "oneofname", descriptor_->oneof_decl(i)->name());
+ map<string, string> oneof_vars;
+ oneof_vars["classname"] = classname_;
+ oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name();
+ string message_class;
+
+ if (use_dependent_base_) {
+ oneof_vars["tmpl"] = "template<class T>\n";
+ oneof_vars["inline"] = "inline ";
+ oneof_vars["dependent_classname"] =
+ DependentBaseClassTemplateName(descriptor_) + "<T>";
+ oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->";
+ message_class = "T::";
+ } else {
+ oneof_vars["tmpl"] = "";
+ oneof_vars["inline"] = "";
+ oneof_vars["dependent_classname"] = classname_;
+ oneof_vars["this_message"] = "";
+ }
+
+ printer->Print(oneof_vars,
+ "$tmpl$"
+ "$inline$"
+ "void $dependent_classname$::clear_$oneofname$() {\n");
printer->Indent();
- printer->Print(
- "switch($oneofname$_case()) {\n",
- "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Print(oneof_vars,
+ "switch($this_message$$oneofname$_case()) {\n");
printer->Indent();
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
printer->Print(
- "case k$field_name$: {\n",
+ "case $message_class$k$field_name$: {\n",
+ "message_class", message_class,
"field_name", UnderscoresToCamelCase(field->name(), true));
printer->Indent();
// We clear only allocated objects in oneofs
@@ -2213,16 +2524,20 @@ GenerateOneofClear(io::Printer* printer) {
"}\n");
}
printer->Print(
- "case $cap_oneof_name$_NOT_SET: {\n"
+ "case $message_class$$cap_oneof_name$_NOT_SET: {\n"
" break;\n"
"}\n",
+ "message_class", message_class,
"cap_oneof_name",
ToUpper(descriptor_->oneof_decl(i)->name()));
printer->Outdent();
printer->Print(
"}\n"
- "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n",
+ "$this_message$_oneof_case_[$oneof_index$] = "
+ "$message_class$$cap_oneof_name$_NOT_SET;\n",
+ "this_message", oneof_vars["this_message"],
"oneof_index", SimpleItoa(i),
+ "message_class", message_class,
"cap_oneof_name",
ToUpper(descriptor_->oneof_decl(i)->name()));
printer->Outdent();
@@ -2333,9 +2648,9 @@ GenerateMergeFrom(io::Printer* printer) {
// system, as the GOOGLE_CHECK above ensured that we have the same descriptor
// for each message.
printer->Print(
- "const $classname$* source =\n"
- " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
- " &from);\n"
+ "const $classname$* source = \n"
+ " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n"
+ " &from);\n"
"if (source == NULL) {\n"
" ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
"} else {\n"
@@ -2585,8 +2900,24 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Indent();
+ // Find repeated messages and groups now, to simplify what follows.
+ hash_set<int> fields_with_parse_loop;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+ if (field->is_repeated() &&
+ (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+ field->type() == FieldDescriptor::TYPE_GROUP)) {
+ fields_with_parse_loop.insert(i);
+ }
+ }
+
+ // need_label is true if we generated "goto parse_$name$" while handling the
+ // previous field.
+ bool need_label = false;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = ordered_fields[i];
+ const bool loops = fields_with_parse_loop.count(i) > 0;
+ const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0;
PrintFieldComment(printer, field);
@@ -2600,9 +2931,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("if (tag == $commontag$) {\n",
"commontag", SimpleItoa(WireFormat::MakeTag(field)));
- if (i > 0 || (field->is_repeated() && !field->options().packed())) {
+ if (need_label ||
+ (field->is_repeated() && !field->options().packed() && !loops)) {
+ printer->Print(
+ " parse_$name$:\n",
+ "name", field->name());
+ }
+ if (loops) {
printer->Print(
- " parse_$name$:\n",
+ " DO_(input->IncrementRecursionDepth());\n"
+ " parse_loop_$name$:\n",
"name", field->name());
}
@@ -2644,26 +2982,53 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// switch() is slow since it can't be predicted well. Insert some if()s
// here that attempt to predict the next tag.
- if (field->is_repeated() && !field->options().packed()) {
- // Expect repeats of this field.
+ // For non-packed repeated fields, expect the same tag again.
+ if (loops) {
+ printer->Print(
+ "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n",
+ "tag", SimpleItoa(WireFormat::MakeTag(field)),
+ "name", field->name());
+ } else if (field->is_repeated() && !field->options().packed()) {
printer->Print(
"if (input->ExpectTag($tag$)) goto parse_$name$;\n",
"tag", SimpleItoa(WireFormat::MakeTag(field)),
"name", field->name());
}
- if (i + 1 < descriptor_->field_count()) {
- // Expect the next field in order.
- const FieldDescriptor* next_field = ordered_fields[i + 1];
- printer->Print(
- "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
- "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
- "next_name", next_field->name());
- } else {
- // Expect EOF.
- // TODO(kenton): Expect group end-tag?
+ // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet?
+ bool emitted_goto_next_tag = false;
+
+ // For repeated messages/groups, we need to decrement recursion depth,
+ // unless the next tag is also for a repeated message/group.
+ if (loops) {
+ if (next_field_loops) {
+ const FieldDescriptor* next_field = ordered_fields[i + 1];
+ printer->Print(
+ "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n",
+ "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+ "next_name", next_field->name());
+ emitted_goto_next_tag = true;
+ }
printer->Print(
- "if (input->ExpectAtEnd()) goto success;\n");
+ "input->UnsafeDecrementRecursionDepth();\n");
+ }
+
+ // If there are more fields, expect the next one.
+ need_label = false;
+ if (!emitted_goto_next_tag) {
+ if (i + 1 == descriptor_->field_count()) {
+ // Expect EOF.
+ // TODO(kenton): Expect group end-tag?
+ printer->Print(
+ "if (input->ExpectAtEnd()) goto success;\n");
+ } else {
+ const FieldDescriptor* next_field = ordered_fields[i + 1];
+ printer->Print(
+ "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
+ "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+ "next_name", next_field->name());
+ need_label = true;
+ }
}
printer->Print(
@@ -2999,9 +3364,7 @@ static string ConditionalToCheckBitmasks(const vector<uint32>& masks) {
vector<string> parts;
for (int i = 0; i < masks.size(); i++) {
if (masks[i] == 0) continue;
- char buffer[kFastToBufferSize];
- FastHex32ToBuffer(masks[i], buffer);
- string m = StrCat("0x", buffer);
+ string m = StrCat("0x", strings::Hex(masks[i], strings::Hex::ZERO_PAD_8));
// Each xor evaluates to 0 if the expected bits are present.
parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
}
@@ -3293,11 +3656,10 @@ GenerateIsInitialized(io::Printer* printer) {
}
if (mask != 0) {
- char buffer[kFastToBufferSize];
printer->Print(
"if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
"i", SimpleItoa(i),
- "mask", FastHex32ToBuffer(mask, buffer));
+ "mask", StrCat(strings::Hex(mask, strings::Hex::ZERO_PAD_8)));
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index ea96581d..23dad10c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -67,7 +67,8 @@ class MessageGenerator {
// Header stuff.
// Generate foward declarations for this class and all its nested types.
- void GenerateForwardDeclaration(io::Printer* printer);
+ void GenerateMessageForwardDeclaration(io::Printer* printer);
+ void GenerateEnumForwardDeclaration(io::Printer* printer);
// Generate definitions of all nested enums (must come before class
// definitions because those classes use the enums definitions).
@@ -84,6 +85,9 @@ class MessageGenerator {
// file).
void GenerateInlineMethods(io::Printer* printer, bool is_inline);
+ // Dependent methods are always inline.
+ void GenerateDependentInlineMethods(io::Printer* printer);
+
// Source file stuff.
// Generate code which declares all the global descriptor pointers which
@@ -115,7 +119,10 @@ class MessageGenerator {
private:
// Generate declarations and definitions of accessors for fields.
+ void GenerateDependentBaseClassDefinition(io::Printer* printer);
+ void GenerateDependentFieldAccessorDeclarations(io::Printer* printer);
void GenerateFieldAccessorDeclarations(io::Printer* printer);
+ void GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
// Generate the field offsets array.
@@ -158,6 +165,21 @@ class MessageGenerator {
bool unbounded);
+ // Generates has_foo() functions and variables for singular field has-bits.
+ void GenerateSingularFieldHasBits(const FieldDescriptor* field,
+ map<string, string> vars,
+ io::Printer* printer);
+ // Generates has_foo() functions and variables for oneof field has-bits.
+ void GenerateOneofHasBits(io::Printer* printer, bool is_inline);
+ // Generates has_foo_bar() functions for oneof members.
+ void GenerateOneofMemberHasBits(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer);
+ // Generates the clear_foo() method for a field.
+ void GenerateFieldClear(const FieldDescriptor* field,
+ const map<string, string>& vars,
+ io::Printer* printer);
+
const Descriptor* descriptor_;
string classname_;
Options options_;
@@ -168,6 +190,7 @@ class MessageGenerator {
google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
int num_required_fields_;
bool uses_string_;
+ bool use_dependent_base_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 467b6bf6..ba318d10 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -72,7 +72,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
MessageFieldGenerator::
MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
- : descriptor_(descriptor) {
+ : descriptor_(descriptor),
+ dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
SetMessageVariables(descriptor, &variables_, options);
}
@@ -84,6 +85,10 @@ GeneratePrivateMembers(io::Printer* printer) const {
}
void MessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
@@ -144,6 +149,8 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
" return temp;\n"
"}\n");
if (SupportsArenas(descriptor_->message_type())) {
+ // NOTE: the same logic is mirrored in weak_message_field.cc. Any
+ // arena-related semantics changes should be made in both places.
printer->Print(variables_,
"void $classname$::_slow_set_allocated_$name$(\n"
" ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
@@ -181,6 +188,10 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
}
void MessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const {
map<string, string> variables(variables_);
@@ -294,7 +305,7 @@ GenerateClearingCode(io::Printer* printer) const {
// If we don't have has-bits, message presence is indicated only by ptr !=
// NULL. Thus on clear, we need to delete the object.
printer->Print(variables_,
- "if ($name$_ != NULL) delete $name$_;\n"
+ "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n"
"$name$_ = NULL;\n");
} else {
printer->Print(variables_,
@@ -366,6 +377,10 @@ MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
void MessageOneofFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const {
map<string, string> variables(variables_);
@@ -560,6 +575,10 @@ GeneratePrivateMembers(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"const $type$& $name$(int index) const$deprecation$;\n"
@@ -573,6 +592,10 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const {
map<string, string> variables(variables_);
@@ -627,11 +650,13 @@ void RepeatedMessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+ "DO_(::google::protobuf::internal::WireFormatLite::"
+ "ReadMessageNoVirtualNoRecursionDepth(\n"
" input, add_$name$()));\n");
} else {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+ "DO_(::google::protobuf::internal::WireFormatLite::"
+ "ReadGroupNoVirtualNoRecursionDepth(\n"
" $number$, input, add_$name$()));\n");
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index c1704fc1..9ddf9643 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -52,7 +52,9 @@ class MessageFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
@@ -67,6 +69,7 @@ class MessageFieldGenerator : public FieldGenerator {
protected:
const FieldDescriptor* descriptor_;
+ const bool dependent_field_;
map<string, string> variables_;
private:
@@ -80,6 +83,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
~MessageOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
@@ -99,7 +103,9 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 0c99cff1..4463f200 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -41,12 +41,13 @@ namespace protobuf {
namespace compiler {
namespace cpp {
-// Generator options:
+// Generator options (see generator.cc for a description of each):
struct Options {
- Options() : safe_boundary_check(false) {
+ Options() : safe_boundary_check(false), proto_h(false) {
}
string dllexport_decl;
bool safe_boundary_check;
+ bool proto_h;
};
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 329eae32..9f929d37 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -262,7 +262,7 @@ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
: descriptor_(descriptor) {
SetPrimitiveVariables(descriptor, &variables_, options);
- if (descriptor->options().packed()) {
+ if (descriptor->is_packed()) {
variables_["packed_reader"] = "ReadPackedPrimitive";
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
} else {
@@ -277,7 +277,7 @@ void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
- if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+ if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
@@ -364,7 +364,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -377,7 +377,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
" this->$name$(i), output);\n");
@@ -391,7 +391,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
@@ -405,7 +405,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
@@ -435,7 +435,7 @@ GenerateByteSize(io::Printer* printer) const {
"data_size = $fixed_size$ * this->$name$_size();\n");
}
- if (descriptor_->options().packed()) {
+ if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 1a1bcd3d..1a3896a1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -226,7 +226,6 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" } else {\n"
" $clear_hasbit$\n"
" }\n"
- " $set_hasbit$\n"
" $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
" $name$, GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 9f63155b..4e25b2ea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -131,23 +131,23 @@ message TestConflictingSymbolNamesExtension { // NO_PROTO3
} // NO_PROTO3
} // NO_PROTO3
-message TestConflictingEnumNames {
- enum NestedConflictingEnum {
- and = 1;
- class = 2;
- int = 3;
- typedef = 4;
- XOR = 5;
- }
-
- optional NestedConflictingEnum conflicting_enum = 1;
-}
-
-enum ConflictingEnum {
- NOT_EQ = 1;
- volatile = 2;
- return = 3;
-}
+message TestConflictingEnumNames { // NO_PROTO3
+ enum NestedConflictingEnum { // NO_PROTO3
+ and = 1; // NO_PROTO3
+ class = 2; // NO_PROTO3
+ int = 3; // NO_PROTO3
+ typedef = 4; // NO_PROTO3
+ XOR = 5; // NO_PROTO3
+ } // NO_PROTO3
+
+ optional NestedConflictingEnum conflicting_enum = 1; // NO_PROTO3
+} // NO_PROTO3
+
+enum ConflictingEnum { // NO_PROTO3
+ NOT_EQ = 1; // NO_PROTO3
+ volatile = 2; // NO_PROTO3
+ return = 3; // NO_PROTO3
+} // NO_PROTO3
message DummyMessage {}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 9d14a924..b11fb21a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -941,6 +941,22 @@ TEST(GeneratedMessageTest, ExtensionConstantValues) {
EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
}
+TEST(GeneratedMessageTest, ParseFromTruncated) {
+ const string long_string = string(128, 'q');
+ FileDescriptorProto p;
+ p.add_extension()->set_name(long_string);
+ const string msg = p.SerializeAsString();
+ int successful_count = 0;
+ for (int i = 0; i <= msg.size(); i++) {
+ if (p.ParseFromArray(msg.c_str(), i)) {
+ ++successful_count;
+ }
+ }
+ // We don't really care about how often we succeeded.
+ // As long as we didn't crash, we're happy.
+ EXPECT_GE(successful_count, 1);
+}
+
// ===================================================================
TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
new file mode 100644
index 00000000..cb6ca1b1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+ enum EnumWithLargeValue {
+ VALUE_1 = 1;
+ VALUE_MAX = 0x7fffffff;
+ }
+}