aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler/cpp/cpp_helpers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_helpers.cc')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc359
1 files changed, 207 insertions, 152 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index bc0a9264..472c55f4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -53,6 +53,8 @@
#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/port_def.inc>
+
namespace google {
namespace protobuf {
namespace compiler {
@@ -487,10 +489,9 @@ string DefaultValue(const Options& options, const FieldDescriptor* field) {
case FieldDescriptor::CPPTYPE_UINT32:
return SimpleItoa(field->default_value_uint32()) + "u";
case FieldDescriptor::CPPTYPE_INT64:
- return Int64ToString(MacroPrefix(options), field->default_value_int64());
+ return Int64ToString("PROTOBUF", field->default_value_int64());
case FieldDescriptor::CPPTYPE_UINT64:
- return UInt64ToString(MacroPrefix(options),
- field->default_value_uint64());
+ return UInt64ToString("PROTOBUF", field->default_value_uint64());
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field->default_value_double();
if (value == std::numeric_limits<double>::infinity()) {
@@ -1058,7 +1059,7 @@ void ListAllTypesForServices(const FileDescriptor* fd,
bool GetBootstrapBasename(const Options& options, const string& basename,
string* bootstrap_basename) {
- if (options.opensource_runtime) {
+ if (options.opensource_runtime || options.lite_implicit_weak_fields) {
return false;
}
@@ -1169,6 +1170,193 @@ bool ShouldRepeat(const FieldDescriptor* descriptor,
wiretype != internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
}
+void GenerateLengthDelim(
+ const FieldDescriptor* field, const Options& options,
+ MessageSCCAnalyzer* scc_analyzer,
+ const Formatter& format) {
+ format(
+ "ptr = Varint::Parse32Inline(ptr, &size);\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
+ if (!IsProto1(field->file(), options) && field->is_packable()) {
+ if (!HasPreservingUnknownEnumSemantics(field->file()) &&
+ field->type() == FieldDescriptor::TYPE_ENUM) {
+ format(
+ "ctx->extra_parse_data().SetEnumValidator($1$_IsValid, "
+ "msg->mutable_unknown_fields(), $2$);\n"
+ "parser_till_end = "
+ "::$proto_ns$::internal::PackedValidEnumParser$3$;\n"
+ "object = msg->mutable_$4$();\n",
+ QualifiedClassName(field->enum_type()), field->number(),
+ UseUnknownFieldSet(field->file(), options) ? "" : "Lite",
+ FieldName(field));
+ } else {
+ format(
+ "parser_till_end = ::$proto_ns$::internal::Packed$1$Parser;\n"
+ "object = msg->mutable_$2$();\n",
+ DeclaredTypeMethodName(field->type()), FieldName(field));
+ }
+ format(
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "auto newend = ptr + size;\n"
+ "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
+ } else {
+ auto field_type = field->type();
+ if (IsProto1(field->file(), options)) {
+ if (field->is_packable()) {
+ // Sigh ... packed fields endup as a string in proto1
+ field_type = FieldDescriptor::TYPE_BYTES;
+ }
+ if (field_type == FieldDescriptor::TYPE_STRING) {
+ // In proto1 strings are treated as bytes
+ field_type = FieldDescriptor::TYPE_BYTES;
+ }
+ }
+ string utf8 = "";
+ switch (field_type) {
+ case FieldDescriptor::TYPE_STRING:
+ utf8 = GetUtf8Suffix(field, options);
+ if (!utf8.empty()) {
+ string name = "nullptr";
+ if (HasDescriptorMethods(field->file(), options)) {
+ name = "\"" + field->full_name() + "\"";
+ }
+ format("ctx->extra_parse_data().SetFieldName($1$);\n", name);
+ }
+ PROTOBUF_FALLTHROUGH_INTENDED;
+ case FieldDescriptor::TYPE_BYTES: {
+ if (field->options().ctype() == FieldOptions::STRING ||
+ (IsProto1(field->file(), options) &&
+ field->options().ctype() == FieldOptions::STRING_PIECE)) {
+ format(
+ "parser_till_end = ::$proto_ns$::internal::StringParser$1$;\n"
+ "$string$* str = msg->$2$_$3$();\n"
+ "str->clear();\n",
+ utf8,
+ field->is_repeated() && !field->is_map() &&
+ !field->is_packable()
+ ? "add"
+ : "mutable",
+ FieldName(field));
+ if (utf8.empty()) {
+ // special case if there is no utf8 verification.
+ format(
+ "object = str;\n"
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "str->append(ptr, size);\n"
+ "ptr += size;\n");
+ return;
+ }
+ } else if (field->options().ctype() == FieldOptions::CORD) {
+ string cord_parser = "CordParser" + utf8;
+ format(
+ "parser_till_end = ::$proto_ns$::internal::$1$;\n"
+ "auto* str = msg->$2$_$3$();\n"
+ "str->Clear();\n",
+ cord_parser,
+ field->is_repeated() && !field->is_map() ? "add" : "mutable",
+ FieldName(field));
+ } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
+ format(
+ "parser_till_end = "
+ "::$proto_ns$::internal::StringPieceParser$1$;\n"
+ "::$proto_ns$::internal::StringPieceField* str = "
+ "msg->$2$_$3$();\n"
+ "str->Clear();\n",
+ utf8,
+ field->is_repeated() && !field->is_map() ? "add" : "mutable",
+ FieldName(field));
+ }
+ format(
+ "object = str;\n"
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "auto newend = ptr + size;\n"
+ "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n");
+ if (!utf8.empty()) {
+ // If utf8 verification is on this can fail.
+ format("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
+ }
+ break;
+ }
+ case FieldDescriptor::TYPE_MESSAGE: {
+ GOOGLE_CHECK(field->message_type());
+ if (!IsProto1(field->file(), options) && field->is_map()) {
+ const FieldDescriptor* val =
+ field->message_type()->FindFieldByName("value");
+ GOOGLE_CHECK(val);
+ if (HasFieldPresence(field->file()) &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ format(
+ "ctx->extra_parse_data().field_number = $1$;\n"
+ "ctx->extra_parse_data().unknown_fields = "
+ "&msg->_internal_metadata_;\n",
+ field->number());
+ }
+ format(
+ "parser_till_end = ::$proto_ns$::internal::SlowMapEntryParser;\n"
+ "auto parse_map = $1$::_ParseMap;\n"
+ "ctx->extra_parse_data().payload.clear();\n"
+ "ctx->extra_parse_data().parse_map = parse_map;\n"
+ "object = &msg->$2$_;\n"
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "auto newend = ptr + size;\n"
+ "GOOGLE_PROTOBUF_PARSER_ASSERT(parse_map(ptr, newend, "
+ "object, ctx));\n"
+ "ptr = newend;\n",
+ QualifiedClassName(field->message_type()), FieldName(field));
+ break;
+ }
+ if (IsImplicitWeakField(field, options, scc_analyzer)) {
+ if (!field->is_repeated()) {
+ format("object = HasBitSetters::mutable_$1$(msg);\n",
+ FieldName(field));
+ } else {
+ format(
+ "object = "
+ "CastToBase(&msg->$1$_)->AddWeak(reinterpret_cast<const "
+ "::google::protobuf::MessageLite*>(&$2$::_$3$_default_instance_));\n",
+ FieldName(field), Namespace(field->message_type()),
+ ClassName(field->message_type()));
+ }
+ format(
+ "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
+ "object)->_ParseFunc();\n");
+ } else if (IsWeak(field, options)) {
+ if (IsProto1(field->file(), options)) {
+ format("object = msg->internal_mutable_$1$();\n",
+ FieldName(field));
+ } else {
+ format(
+ "object = msg->_weak_field_map_.MutableMessage($1$, "
+ "_$classname$_default_instance_.$2$_);\n",
+ field->number(), FieldName(field));
+ }
+ format(
+ "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
+ "object)->_ParseFunc();\n");
+ } else {
+ format(
+ "parser_till_end = $1$::_InternalParse;\n"
+ "object = msg->$2$_$3$();\n",
+ QualifiedClassName(field->message_type()),
+ field->is_repeated() ? "add" : "mutable", FieldName(field));
+ }
+ format(
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "auto newend = ptr + size;\n"
+ "bool ok = ctx->ParseExactRange({parser_till_end, object},\n"
+ " ptr, newend);\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
+ "ptr = newend;\n");
+ break;
+ }
+ default:
+ GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype "
+ << " filed type is " << field->type();
+ }
+ }
+}
+
void GenerateCaseBody(internal::WireFormatLite::WireType wiretype,
const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer,
@@ -1185,10 +1373,11 @@ void GenerateCaseBody(internal::WireFormatLite::WireType wiretype,
format(
"$uint64$ val;\n"
"ptr = Varint::Parse64(ptr, &val);\n"
- "if (!ptr) goto error;\n");
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
string type = PrimitiveTypeName(options, field->cpp_type());
- if (field->type() == FieldDescriptor::TYPE_SINT32 ||
- field->type() == FieldDescriptor::TYPE_SINT64) {
+ if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
+ field->type() == FieldDescriptor::TYPE_SINT64) &&
+ !IsProto1(field->file(), options)) {
int size = EstimateAlignmentSize(field) * 8;
format(
"$1$ value = "
@@ -1232,149 +1421,17 @@ void GenerateCaseBody(internal::WireFormatLite::WireType wiretype,
break;
}
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
- format(
- "ptr = Varint::Parse32Inline(ptr, &size);\n"
- "if (!ptr) goto error;\n");
- if (!IsProto1(field->file(), options) && field->is_packable()) {
- if (!HasPreservingUnknownEnumSemantics(field->file()) &&
- field->type() == FieldDescriptor::TYPE_ENUM) {
- format(
- "ctx->extra_parse_data().SetEnumValidator($1$_IsValid, "
- "msg->mutable_unknown_fields(), $2$);\n"
- "parser_till_end = "
- "::$proto_ns$::internal::PackedValidEnumParser$3$;\n"
- "object = msg->mutable_$4$();\n",
- QualifiedClassName(field->enum_type()), field->number(),
- UseUnknownFieldSet(field->file(), options) ? "" : "Lite",
- FieldName(field));
- } else {
- format(
- "parser_till_end = ::$proto_ns$::internal::Packed$1$Parser;\n"
- "object = msg->mutable_$2$();\n",
- DeclaredTypeMethodName(field->type()), FieldName(field));
- }
- } else {
- auto field_type = field->type();
- if (IsProto1(field->file(), options)) {
- if (field->is_packable()) {
- // Sigh ... packed fields endup as a string in proto1
- field_type = FieldDescriptor::TYPE_BYTES;
- }
- if (field_type == FieldDescriptor::TYPE_STRING) {
- // In proto1 strings are treated as bytes
- field_type = FieldDescriptor::TYPE_BYTES;
- }
- }
- string utf8 = "";
- switch (field_type) {
- case FieldDescriptor::TYPE_STRING:
- utf8 = GetUtf8Suffix(field, options);
- if (!utf8.empty()) {
- string name = "nullptr";
- if (HasDescriptorMethods(field->file(), options)) {
- name = field->full_name();
- }
- format("ctx->extra_parse_data().SetFieldName(\"$1$\");\n", name);
- }
- [[clang::fallthrough]];
- case FieldDescriptor::TYPE_BYTES: {
- if (field->options().ctype() == FieldOptions::STRING ||
- (IsProto1(field->file(), options) &&
- field->options().ctype() == FieldOptions::STRING_PIECE)) {
- format(
- "parser_till_end = ::$proto_ns$::internal::StringParser$1$;\n"
- "$string$* str = msg->$2$_$3$();\n"
- "str->clear();\n",
- utf8,
- field->is_repeated() && !field->is_map() &&
- !field->is_packable()
- ? "add"
- : "mutable",
- FieldName(field));
- } else if (field->options().ctype() == FieldOptions::CORD) {
- string cord_parser = "CordParser" + utf8;
- format(
- "parser_till_end = ::$proto_ns$::internal::$1$;\n"
- "auto* str = msg->$2$_$3$();\n"
- "str->Clear();\n",
- cord_parser,
- field->is_repeated() && !field->is_map() ? "add" : "mutable",
- FieldName(field));
- } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
- format(
- "parser_till_end = "
- "::$proto_ns$::internal::StringPieceParser$1$;\n"
- "::$proto_ns$::internal::StringPieceField* str = "
- "msg->$2$_$3$();\n"
- "str->Clear();\n",
- utf8,
- field->is_repeated() && !field->is_map() ? "add" : "mutable",
- FieldName(field));
- }
- format("object = str;\n");
- break;
- }
- case FieldDescriptor::TYPE_MESSAGE: {
- GOOGLE_CHECK(field->message_type());
- if (IsImplicitWeakField(field, options, scc_analyzer)) {
- if (!field->is_repeated()) {
- format("object = HasBitSetters::mutable_$1$(msg);\n",
- FieldName(field));
- } else {
- format(
- "object = "
- "CastToBase(&msg->$1$_)->AddWeak(reinterpret_cast<const "
- "::google::protobuf::MessageLite*>(&$2$::_$3$_default_instance_));\n",
- FieldName(field), Namespace(field->message_type()),
- ClassName(field->message_type()));
- }
- format(
- "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
- "object)->_ParseFunc();\n");
- break;
- } else if (IsWeak(field, options)) {
- if (IsProto1(field->file(), options)) {
- format("object = msg->internal_mutable_$1$();\n",
- FieldName(field));
- } else {
- format(
- "object = msg->_weak_field_map_.MutableMessage($1$, "
- "_$classname$_default_instance_.$2$_);\n",
- field->number(), FieldName(field));
- }
- format(
- "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
- "object)->_ParseFunc();\n");
- break;
- }
- format(
- "parser_till_end = $1$::_InternalParse;\n"
- "object = msg->$2$_$3$();\n",
- QualifiedClassName(field->message_type()),
- field->is_repeated() && !field->is_map() ? "add" : "mutable",
- FieldName(field));
- break;
- }
- default:
- GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype "
- << " filed type is " << field->type();
- }
- }
- format(
- "if (size > end - ptr) goto len_delim_till_end;\n"
- "auto newend = ptr + size;\n"
- "if (!ctx->ParseExactRange({parser_till_end, object}, ptr, newend)) "
- "goto error;\n"
- "ptr = newend;\n");
+ GenerateLengthDelim(field, options, scc_analyzer, format);
break;
}
case WireFormatLite::WIRETYPE_START_GROUP: {
format(
"parser_till_end = $1$::_InternalParse;\n"
"object = msg->$2$_$3$();\n"
- "if (!ctx->PrepareGroup(tag, &depth)) goto error;\n"
+ "bool ok = ctx->PrepareGroup(tag, &depth);\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
"ptr = parser_till_end(ptr, end, object, ctx);\n"
- "if (!ptr) goto error;\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
"if (ctx->GroupContinues(depth)) goto group_continues;\n",
QualifiedClassName(field->message_type()),
field->is_repeated() ? "add" : "mutable", FieldName(field));
@@ -1413,8 +1470,8 @@ void GenerateCaseBody(internal::WireFormatLite::WireType wiretype,
uint64 mask = (1ull << (cnt * 8)) - 1;
format.Outdent();
format(
- "} while((*reinterpret_cast<const $uint64$*>(ptr) & $1$) == $2$ && "
- "(ptr += $3$));\n",
+ "} while ((::$proto_ns$::io::UnalignedLoad<$uint64$>(ptr) & $1$) == "
+ "$2$ && (ptr += $3$));\n",
mask, y, cnt);
}
format("break;\n");
@@ -1491,9 +1548,8 @@ void GenerateParserLoop(const Descriptor* descriptor, const Options& options,
" while (ptr < end) {\n"
" $uint32$ tag;\n"
" ptr = Varint::Parse32Inline(ptr, &tag);\n"
- " if (!ptr) goto error;\n"
- " switch (tag >> 3) {\n"
- " case 0: goto error;\n");
+ " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
+ " switch (tag >> 3) {\n");
format.Indent();
format.Indent();
@@ -1526,8 +1582,9 @@ void GenerateParserLoop(const Descriptor* descriptor, const Options& options,
format(
"default: {\n"
"handle_unusual: (void)&&handle_unusual;\n"
- " if ((tag & 7) == 4) {\n"
- " if (!ctx->ValidEndGroup(tag)) goto error;\n"
+ " if ((tag & 7) == 4 || tag == 0) {\n"
+ " bool ok = ctx->ValidEndGroup(tag);\n"
+ " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
" return ptr;\n"
" }\n");
if (IsMapEntryMessage(descriptor)) {
@@ -1579,8 +1636,6 @@ void GenerateParserLoop(const Descriptor* descriptor, const Options& options,
" } // switch\n"
" } // while\n"
" return ptr;\n"
- "error:\n"
- " return nullptr;\n"
"len_delim_till_end: (void)&&len_delim_till_end;\n"
" return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},\n"
" {parser_till_end, object}, size);\n"