From ce9dcc24559a367c42fa2ec8d32f399e681ada1b Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Fri, 3 Nov 2023 22:38:26 +0000 Subject: [PATCH] Auto-generate files after cl/579321454 --- php/ext/google/protobuf/php-upb.c | 866 +++++++++++++++++++++----- php/ext/google/protobuf/php-upb.h | 170 ++++- ruby/ext/google/protobuf_c/ruby-upb.c | 866 +++++++++++++++++++++----- ruby/ext/google/protobuf_c/ruby-upb.h | 170 ++++- 4 files changed, 1684 insertions(+), 388 deletions(-) diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index f999768b48..f20fc800d8 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -319,8 +319,13 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE0) +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif @@ -5880,6 +5885,289 @@ bool upb_Message_IsExactlyEqual(const upb_Message* m1, const upb_Message* m2, } +#include +#include + + +// Must be last. + +static bool upb_MessageField_IsMap(const upb_MiniTableField* field) { + return upb_FieldMode_Get(field) == kUpb_FieldMode_Map; +} + +static upb_StringView upb_Clone_StringView(upb_StringView str, + upb_Arena* arena) { + if (str.size == 0) { + return upb_StringView_FromDataAndSize(NULL, 0); + } + void* cloned_data = upb_Arena_Malloc(arena, str.size); + upb_StringView cloned_str = + upb_StringView_FromDataAndSize(cloned_data, str.size); + memcpy(cloned_data, str.data, str.size); + return cloned_str; +} + +static bool upb_Clone_MessageValue(void* value, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + switch (value_type) { + case kUpb_CType_Bool: + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return true; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView source = *(upb_StringView*)value; + int size = source.size; + void* cloned_data = upb_Arena_Malloc(arena, size); + if (cloned_data == NULL) { + return false; + } + *(upb_StringView*)value = + upb_StringView_FromDataAndSize(cloned_data, size); + memcpy(cloned_data, source.data, size); + return true; + } break; + case kUpb_CType_Message: { + const upb_TaggedMessagePtr source = *(upb_TaggedMessagePtr*)value; + bool is_empty = upb_TaggedMessagePtr_IsEmpty(source); + if (is_empty) sub = &_kUpb_MiniTable_Empty; + UPB_ASSERT(source); + upb_Message* clone = upb_Message_DeepClone( + _upb_TaggedMessagePtr_GetMessage(source), sub, arena); + *(upb_TaggedMessagePtr*)value = + _upb_TaggedMessagePtr_Pack(clone, is_empty); + return clone != NULL; + } break; + } + UPB_UNREACHABLE(); +} + +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena) { + upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size); + if (cloned_map == NULL) { + return NULL; + } + upb_MessageValue key, val; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map, &key, &val, &iter)) { + const upb_MiniTableField* value_field = &map_entry_table->fields[1]; + const upb_MiniTable* value_sub = + (value_field->UPB_PRIVATE(submsg_index) != kUpb_NoSub) + ? upb_MiniTable_GetSubMessageTable(map_entry_table, value_field) + : NULL; + upb_CType value_field_type = upb_MiniTableField_CType(value_field); + if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) { + return NULL; + } + if (upb_Map_Insert(cloned_map, key, val, arena) == + kUpb_MapInsertStatus_OutOfMemory) { + return NULL; + } + } + return cloned_map; +} + +static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, + upb_Arena* arena) { + const upb_MiniTable* map_entry_table = + mini_table->subs[field->UPB_PRIVATE(submsg_index)].submsg; + UPB_ASSERT(map_entry_table); + + const upb_MiniTableField* key_field = &map_entry_table->fields[0]; + const upb_MiniTableField* value_field = &map_entry_table->fields[1]; + + upb_Map* cloned_map = upb_Map_DeepClone( + map, upb_MiniTableField_CType(key_field), + upb_MiniTableField_CType(value_field), map_entry_table, arena); + if (!cloned_map) { + return NULL; + } + _upb_Message_SetNonExtensionField(clone, field, &cloned_map); + return cloned_map; +} + +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + size_t size = array->size; + upb_Array* cloned_array = + _upb_Array_New(arena, size, _upb_Array_CTypeSizeLg2(value_type)); + if (!cloned_array) { + return NULL; + } + if (!_upb_Array_ResizeUninitialized(cloned_array, size, arena)) { + return NULL; + } + for (size_t i = 0; i < size; ++i) { + upb_MessageValue val = upb_Array_Get(array, i); + if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) { + return false; + } + upb_Array_Set(cloned_array, i, val); + } + return cloned_array; +} + +static bool upb_Message_Array_DeepClone(const upb_Array* array, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, upb_Arena* arena) { + _upb_MiniTableField_CheckIsArray(field); + upb_Array* cloned_array = upb_Array_DeepClone( + array, upb_MiniTableField_CType(field), + upb_MiniTableField_CType(field) == kUpb_CType_Message && + field->UPB_PRIVATE(submsg_index) != kUpb_NoSub + ? upb_MiniTable_GetSubMessageTable(mini_table, field) + : NULL, + arena); + + // Clear out upb_Array* due to parent memcpy. + _upb_Message_SetNonExtensionField(clone, field, &cloned_array); + return true; +} + +static bool upb_Clone_ExtensionValue( + const upb_MiniTableExtension* mini_table_ext, + const upb_Message_Extension* source, upb_Message_Extension* dest, + upb_Arena* arena) { + dest->data = source->data; + return upb_Clone_MessageValue( + &dest->data, upb_MiniTableField_CType(&mini_table_ext->field), + mini_table_ext->sub.submsg, arena); +} + +upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0); + // Only copy message area skipping upb_Message_Internal. + memcpy(dst, src, mini_table->size); + for (size_t i = 0; i < mini_table->field_count; ++i) { + const upb_MiniTableField* field = &mini_table->fields[i]; + if (!upb_IsRepeatedOrMap(field)) { + switch (upb_MiniTableField_CType(field)) { + case kUpb_CType_Message: { + upb_TaggedMessagePtr tagged = + upb_Message_GetTaggedMessagePtr(src, field, NULL); + const upb_Message* sub_message = + _upb_TaggedMessagePtr_GetMessage(tagged); + if (sub_message != NULL) { + // If the message is currently in an unlinked, "empty" state we keep + // it that way, because we don't want to deal with decode options, + // decode status, or possible parse failure here. + bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged); + const upb_MiniTable* sub_message_table = + is_empty ? &_kUpb_MiniTable_Empty + : upb_MiniTable_GetSubMessageTable(mini_table, field); + upb_Message* dst_sub_message = + upb_Message_DeepClone(sub_message, sub_message_table, arena); + if (dst_sub_message == NULL) { + return NULL; + } + _upb_Message_SetTaggedMessagePtr( + dst, mini_table, field, + _upb_TaggedMessagePtr_Pack(dst_sub_message, is_empty)); + } + } break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView str = upb_Message_GetString(src, field, empty_string); + if (str.size != 0) { + if (!upb_Message_SetString( + dst, field, upb_Clone_StringView(str, arena), arena)) { + return NULL; + } + } + } break; + default: + // Scalar, already copied. + break; + } + } else { + if (upb_MessageField_IsMap(field)) { + const upb_Map* map = upb_Message_GetMap(src, field); + if (map != NULL) { + if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) { + return NULL; + } + } + } else { + const upb_Array* array = upb_Message_GetArray(src, field); + if (array != NULL) { + if (!upb_Message_Array_DeepClone(array, mini_table, field, dst, + arena)) { + return NULL; + } + } + } + } + } + // Clone extensions. + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(src, &ext_count); + for (size_t i = 0; i < ext_count; ++i) { + const upb_Message_Extension* msg_ext = &ext[i]; + const upb_MiniTableField* field = &msg_ext->ext->field; + upb_Message_Extension* dst_ext = + _upb_Message_GetOrCreateExtension(dst, msg_ext->ext, arena); + if (!dst_ext) return NULL; + if (!upb_IsRepeatedOrMap(field)) { + if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) { + return NULL; + } + } else { + upb_Array* msg_array = (upb_Array*)msg_ext->data.ptr; + UPB_ASSERT(msg_array); + upb_Array* cloned_array = + upb_Array_DeepClone(msg_array, upb_MiniTableField_CType(field), + msg_ext->ext->sub.submsg, arena); + if (!cloned_array) { + return NULL; + } + dst_ext->data.ptr = (void*)cloned_array; + } + } + + // Clone unknowns. + size_t unknown_size = 0; + const char* ptr = upb_Message_GetUnknown(src, &unknown_size); + if (unknown_size != 0) { + UPB_ASSERT(ptr); + // Make a copy into destination arena. + if (!_upb_Message_AddUnknown(dst, ptr, unknown_size, arena)) { + return NULL; + } + } + return dst; +} + +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena) { + upb_Message_Clear(dst, mini_table); + return _upb_Message_Copy(dst, src, mini_table, arena) != NULL; +} + +// Deep clones a message using the provided target arena. +// +// Returns NULL on failure. +upb_Message* upb_Message_DeepClone(const upb_Message* message, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + upb_Message* clone = upb_Message_New(mini_table, arena); + return _upb_Message_Copy(clone, message, mini_table, arena); +} + + #include // Must be last. @@ -7968,6 +8256,7 @@ struct upb_DefPool { upb_strtable files; // file_name -> (upb_FileDef*) upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) upb_ExtensionRegistry* extreg; + const UPB_DESC(FeatureSetDefaults) * feature_set_defaults; upb_MiniTablePlatform platform; void* scratch_data; size_t scratch_size; @@ -7980,6 +8269,8 @@ void upb_DefPool_Free(upb_DefPool* s) { upb_gfree(s); } +static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; + upb_DefPool* upb_DefPool_New(void) { upb_DefPool* s = upb_gmalloc(sizeof(*s)); if (!s) return NULL; @@ -7999,6 +8290,10 @@ upb_DefPool* upb_DefPool_New(void) { if (!s->extreg) goto err; s->platform = kUpb_MiniTablePlatform_Native; + s->feature_set_defaults = UPB_DESC(FeatureSetDefaults_parse)( + serialized_defaults, sizeof(serialized_defaults) - 1, s->arena); + + if (!s->feature_set_defaults) goto err; return s; @@ -8007,6 +8302,11 @@ err: return NULL; } +const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s) { + return s->feature_set_defaults; +} + bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, const upb_FieldDef* f) { return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), @@ -8220,7 +8520,11 @@ static const upb_FileDef* upb_DefBuilder_AddFileToPool( remove_filedef(s, builder->file); builder->file = NULL; } - } else if (!builder->arena || !builder->tmp_arena) { + } else if (!builder->arena || !builder->tmp_arena || + !upb_strtable_init(&builder->feature_cache, 16, + builder->tmp_arena) || + !(builder->legacy_features = + UPB_DESC(FeatureSet_new)(builder->tmp_arena))) { _upb_DefBuilder_OomErr(builder); } else { _upb_FileDef_Create(builder, file_proto); @@ -8253,6 +8557,8 @@ static const upb_FileDef* _upb_DefPool_AddFile( upb_DefBuilder ctx = { .symtab = s, + .tmp_buf = NULL, + .tmp_buf_size = 0, .layout = layout, .platform = s->platform, .msg_count = 0, @@ -8435,7 +8741,8 @@ bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { // Must be last. struct upb_EnumDef { - const UPB_DESC(EnumOptions) * opts; + const UPB_DESC(EnumOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTableEnum* layout; // Only for proto2. const upb_FileDef* file; const upb_MessageDef* containing_type; // Could be merged with "file". @@ -8449,8 +8756,10 @@ struct upb_EnumDef { int res_range_count; int res_name_count; int32_t defaultval; - bool is_closed; bool is_sorted; // Whether all of the values are defined in ascending order. +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { @@ -8552,7 +8861,11 @@ const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { return _upb_EnumValueDef_At(e->values, i); } -bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { return e->is_closed; } +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + return UPB_DESC(FeatureSet_enum_type)(e->resolved_features) == + UPB_DESC(FeatureSet_CLOSED); +} bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, upb_StringView* out) { @@ -8621,6 +8934,7 @@ static upb_StringView* _upb_EnumReservedNames_New( static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto) * enum_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e) { const UPB_DESC(EnumValueDescriptorProto)* const* values; const UPB_DESC(EnumDescriptorProto_EnumReservedRange)* const* res_ranges; @@ -8628,6 +8942,10 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, upb_StringView name; size_t n_value, n_res_range, n_res_name; + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + e->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumOptions_features)(e->opts)); + // Must happen before _upb_DefBuilder_Add() e->file = _upb_DefBuilder_File(ctx); @@ -8637,9 +8955,6 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, e->full_name, _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); - e->is_closed = (!UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) && - (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2); - values = UPB_DESC(EnumDescriptorProto_value)(enum_proto, &n_value); bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); @@ -8650,8 +8965,8 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->defaultval = 0; e->value_count = n_value; - e->values = - _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); + e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, + e->resolved_features, e, &e->is_sorted); if (n_value == 0) { _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", @@ -8668,11 +8983,9 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->res_name_count = n_res_name; e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); - UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - upb_inttable_compact(&e->iton, ctx->arena); - if (e->is_closed) { + if (upb_EnumDef_IsClosed(e)) { if (ctx->layout) { UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); e->layout = ctx->layout->enums[ctx->enum_count++]; @@ -8684,10 +8997,11 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, } } -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); // If a containing type is defined then get the full name from that. @@ -8697,7 +9011,7 @@ upb_EnumDef* _upb_EnumDefs_New( upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); for (int i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); + create_enumdef(ctx, name, protos[i], parent_features, &e[i]); e[i].containing_type = containing_type; } return e; @@ -8756,14 +9070,20 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( } +#include + // Must be last. struct upb_EnumValueDef { - const UPB_DESC(EnumValueOptions) * opts; + const UPB_DESC(EnumValueOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_EnumDef* parent; const char* full_name; int32_t number; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { @@ -8820,9 +9140,15 @@ uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { } static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(EnumValueDescriptorProto) * + const UPB_DESC(EnumValueDescriptorProto*) val_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, upb_EnumValueDef* v) { + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + v->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts)); + upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto); v->parent = e; // Must happen prior to _upb_DefBuilder_Add() @@ -8831,17 +9157,32 @@ static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, v->full_name, _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); - UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, - val_proto); - bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); } +static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx, + const upb_EnumDef* e, + const upb_EnumValueDef* v, int n) { + if (upb_EnumDef_IsClosed(e) || n == 0 || v[0].number == 0) return; + + // When the special UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 is enabled, we have to + // exempt proto2 enums from this check, even when we are treating them as + // open. + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 && + upb_FileDef_Syntax(upb_EnumDef_File(e)) == kUpb_Syntax_Proto2) { + return; + } + + _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)", + upb_EnumDef_FullName(e)); +} + // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); @@ -8851,29 +9192,27 @@ upb_EnumValueDef* _upb_EnumValueDefs_New( *is_sorted = true; uint32_t previous = 0; for (int i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); const uint32_t current = v[i].number; if (previous > current) *is_sorted = false; previous = current; } - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - upb_EnumDef_FullName(e)); - } + _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n); return v; } +#include + // Must be last. struct upb_ExtensionRange { - const UPB_DESC(ExtensionRangeOptions) * opts; + const UPB_DESC(ExtensionRangeOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; int32_t start; int32_t end; }; @@ -8899,12 +9238,18 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m) { + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m) { upb_ExtensionRange* r = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); for (int i = 0; i < n; i++) { + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, + UPB_DESC(ExtensionRangeOptions_features)(r[i].opts)); + const int32_t start = UPB_DESC(DescriptorProto_ExtensionRange_start)(protos[i]); const int32_t end = UPB_DESC(DescriptorProto_ExtensionRange_end)(protos[i]); @@ -8924,8 +9269,6 @@ upb_ExtensionRange* _upb_ExtensionRanges_New( r[i].start = start; r[i].end = end; - UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, protos[i]); } return r; @@ -8947,7 +9290,8 @@ typedef struct { } str_t; struct upb_FieldDef { - const UPB_DESC(FieldOptions) * opts; + const UPB_DESC(FieldOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const upb_MessageDef* msgdef; const char* full_name; @@ -8977,13 +9321,9 @@ struct upb_FieldDef { bool has_json_name; bool has_presence; bool is_extension; - bool is_packed; bool is_proto3_optional; upb_FieldType type_; upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { @@ -9052,7 +9392,9 @@ bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { } bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { - return _upb_FieldDef_IsPackable(f) && f->is_packed; + return _upb_FieldDef_IsPackable(f) && + UPB_DESC(FeatureSet_repeated_field_encoding(f->resolved_features)) == + UPB_DESC(FeatureSet_PACKED); } const char* upb_FieldDef_Name(const upb_FieldDef* f) { @@ -9165,44 +9507,21 @@ bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } -// begin:google_only -// static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { -// #if defined(UPB_BOOTSTRAP_STAGE0) -// return true; -// #else -// return UPB_DESC(FieldOptions_enforce_utf8)(f->opts); -// #endif -// } -// end:google_only - -// begin:github_only -static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { - return true; -} -// end:github_only - bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; - return upb_FileDef_Syntax(upb_FieldDef_File(f)) == kUpb_Syntax_Proto3 - ? _upb_FieldDef_EnforceUtf8Option(f) - : false; + return UPB_DESC(FeatureSet_utf8_validation(f->resolved_features)) == + UPB_DESC(FeatureSet_VERIFY); } uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; - switch (f->label_) { - case kUpb_Label_Optional: - if (!upb_FieldDef_HasPresence(f)) { - out |= kUpb_FieldModifier_IsProto3Singular; - } - break; - case kUpb_Label_Repeated: - out |= kUpb_FieldModifier_IsRepeated; - break; - case kUpb_Label_Required: - out |= kUpb_FieldModifier_IsRequired; - break; + if (upb_FieldDef_IsRepeated(f)) { + out |= kUpb_FieldModifier_IsRepeated; + } else if (upb_FieldDef_IsRequired(f)) { + out |= kUpb_FieldModifier_IsRequired; + } else if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; } if (_upb_FieldDef_IsClosedEnum(f)) { @@ -9242,7 +9561,8 @@ bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { } bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; + return UPB_DESC(FeatureSet_field_presence)(f->resolved_features) == + UPB_DESC(FeatureSet_LEGACY_REQUIRED); } bool upb_FieldDef_IsString(const upb_FieldDef* f) { @@ -9466,19 +9786,63 @@ static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { } } +static bool _upb_FieldDef_InferLegacyFeatures( + upb_DefBuilder* ctx, upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto*) proto, + const UPB_DESC(FieldOptions*) options, upb_Syntax syntax, + UPB_DESC(FeatureSet*) features) { + bool ret = false; + + if (UPB_DESC(FieldDescriptorProto_label)(proto) == kUpb_Label_Required) { + if (syntax == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + int val = UPB_DESC(FeatureSet_LEGACY_REQUIRED); + UPB_DESC(FeatureSet_set_field_presence(features, val)); + ret = true; + } + + if (UPB_DESC(FieldDescriptorProto_type)(proto) == kUpb_FieldType_Group) { + int val = UPB_DESC(FeatureSet_DELIMITED); + UPB_DESC(FeatureSet_set_message_encoding(features, val)); + ret = true; + } + + if (UPB_DESC(FieldOptions_has_packed)(options)) { + int val = UPB_DESC(FieldOptions_packed)(options) + ? UPB_DESC(FeatureSet_PACKED) + : UPB_DESC(FeatureSet_EXPANDED); + UPB_DESC(FeatureSet_set_repeated_field_encoding(features, val)); + ret = true; + } + +// begin:google_only +// #ifndef UPB_BOOTSTRAP_STAGE0 +// if (syntax == kUpb_Syntax_Proto3 && +// UPB_DESC(FieldOptions_has_enforce_utf8)(options) && +// !UPB_DESC(FieldOptions_enforce_utf8)(options)) { +// int val = UPB_DESC(FeatureSet_UNVERIFIED); +// UPB_DESC(FeatureSet_set_utf8_validation(features, val)); +// ret = true; +// } +// #endif +// // clang-format off +// end:google_only + // clang-format on + + return ret; +} + static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { // Must happen before _upb_DefBuilder_Add() f->file = _upb_DefBuilder_File(ctx); - if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto); - f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto); f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto); @@ -9487,6 +9851,29 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, f->msgdef = m; f->scope.oneof = NULL; + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + upb_Syntax syntax = upb_FileDef_Syntax(f->file); + const UPB_DESC(FeatureSet*) unresolved_features = + UPB_DESC(FieldOptions_features)(f->opts); + bool implicit = false; + + if (syntax != kUpb_Syntax_Editions) { + upb_Message_Clear(ctx->legacy_features, UPB_DESC_MINITABLE(FeatureSet)); + if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, syntax, + ctx->legacy_features)) { + implicit = true; + unresolved_features = ctx->legacy_features; + } + } + + f->resolved_features = _upb_DefBuilder_DoResolveFeatures( + ctx, parent_features, unresolved_features, implicit); + + if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto); if (f->has_json_name) { const upb_StringView sv = @@ -9542,12 +9929,6 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, * to the field_proto until later when we can properly resolve it. */ f->sub.unresolved = field_proto; - if (f->label_ == kUpb_Label_Required && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } - if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { int oneof_index = UPB_DESC(FieldDescriptorProto_oneof_index)(field_proto); @@ -9571,27 +9952,21 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); } - UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (UPB_DESC(FieldOptions_has_packed)(f->opts)) { - f->is_packed = UPB_DESC(FieldOptions_packed)(f->opts); - } else { - f->is_packed = upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; - } - f->has_presence = (!upb_FieldDef_IsRepeated(f)) && (f->type_ == kUpb_FieldType_Message || f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || - (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto2)); + UPB_DESC(FeatureSet_field_presence)(f->resolved_features) != + UPB_DESC(FeatureSet_IMPLICIT)); } static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = true; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", @@ -9608,11 +9983,13 @@ static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, } static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) + parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = false; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (!UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { if (f->is_proto3_optional) { @@ -9626,10 +10003,11 @@ static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, _upb_MessageDef_InsertField(ctx, m, f); } -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m) { +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -9637,17 +10015,19 @@ upb_FieldDef* _upb_Extensions_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; } return defs; } -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted) { +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -9656,7 +10036,7 @@ upb_FieldDef* _upb_FieldDefs_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; if (!ctx->layout) { // Speculate that the def fields are sorted. We will always sort the @@ -9860,11 +10240,14 @@ void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, } +#include + // Must be last. struct upb_FileDef { - const UPB_DESC(FileOptions) * opts; + const UPB_DESC(FileOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const char* name; const char* package; UPB_DESC(Edition) edition; @@ -9894,6 +10277,11 @@ const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f) { return f->opts; } +const UPB_DESC(FeatureSet) * + upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { + return f->resolved_features; +} + bool upb_FileDef_HasOptions(const upb_FileDef* f) { return f->opts != (void*)kUpbDefOptDefault; } @@ -10010,6 +10398,34 @@ static int count_exts_in_msg(const UPB_DESC(DescriptorProto) * msg_proto) { return ext_count; } +const UPB_DESC(FeatureSet*) + _upb_FileDef_FindEdition(upb_DefBuilder* ctx, int edition) { + const UPB_DESC(FeatureSetDefaults)* defaults = + upb_DefPool_FeatureSetDefaults(ctx->symtab); + + int min = UPB_DESC(FeatureSetDefaults_minimum_edition)(defaults); + int max = UPB_DESC(FeatureSetDefaults_maximum_edition)(defaults); + if (edition < min || edition > max) { + _upb_DefBuilder_Errf(ctx, + "Edition %d is outside the supported range [%d, %d] " + "given in the defaults", + edition, min, max); + } + + size_t n; + const UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault)* const* d = + UPB_DESC(FeatureSetDefaults_defaults)(defaults, &n); + const UPB_DESC(FeatureSet)* ret = NULL; + for (size_t i = 0; i < n; i++) { + if (UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_edition)(d[i]) > + edition) { + break; + } + ret = UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_features)(d[i]); + } + return ret; +} + // Allocate and initialize one file def, and add it to the context object. void _upb_FileDef_Create(upb_DefBuilder* ctx, const UPB_DESC(FileDescriptorProto) * file_proto) { @@ -10078,21 +10494,33 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, if (streql_view(syntax, "proto2")) { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } else if (streql_view(syntax, "proto3")) { file->syntax = kUpb_Syntax_Proto3; + file->edition = UPB_DESC(EDITION_PROTO3); } else if (streql_view(syntax, "editions")) { file->syntax = kUpb_Syntax_Editions; + file->edition = UPB_DESC(FileDescriptorProto_edition)(file_proto); } else { _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", UPB_STRINGVIEW_ARGS(syntax)); } } else { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } // Read options. UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + // Resolve features. + const UPB_DESC(FeatureSet*) edition_defaults = + _upb_FileDef_FindEdition(ctx, file->edition); + const UPB_DESC(FeatureSet*) unresolved = + UPB_DESC(FileOptions_features)(file->opts); + file->resolved_features = + _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); + // Verify dependencies. strs = UPB_DESC(FileDescriptorProto_dependency)(file_proto, &n); file->dep_count = n; @@ -10138,22 +10566,26 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, // Create enums. enums = UPB_DESC(FileDescriptorProto_enum_type)(file_proto, &n); file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); + file->top_lvl_enums = + _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); // Create extensions. exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n); file->top_lvl_ext_count = n; - file->top_lvl_exts = _upb_Extensions_New(ctx, n, exts, file->package, NULL); + file->top_lvl_exts = _upb_Extensions_New( + ctx, n, exts, file->resolved_features, file->package, NULL); // Create messages. msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n); file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); + file->top_lvl_msgs = + _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); // Create services. services = UPB_DESC(FileDescriptorProto_service)(file_proto, &n); file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); + file->services = + _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); // Now that all names are in the table, build layouts and resolve refs. @@ -10516,6 +10948,77 @@ void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, UPB_ASSERT(false); } +upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key) { + size_t need = key.size + sizeof(void*); + if (ctx->tmp_buf_size < need) { + ctx->tmp_buf_size = UPB_MAX(64, upb_Log2Ceiling(need)); + ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); + if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); + } + + memcpy(ctx->tmp_buf, &parent, sizeof(void*)); + memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); + return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); +} + +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set) { + upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); + upb_value v; + if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { + *set = upb_value_getptr(v); + return false; + } + + *set = + upb_Message_DeepClone(parent, UPB_DESC_MINITABLE(FeatureSet), ctx->arena); + if (!*set) _upb_DefBuilder_OomErr(ctx); + + v = upb_value_ptr(*set); + if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, + ctx->tmp_arena)) { + _upb_DefBuilder_OomErr(ctx); + } + + return true; +} + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit) { + assert(parent); + if (!child) return parent; + + if (child && !is_implicit && + upb_FileDef_Syntax(ctx->file) != kUpb_Syntax_Editions) { + _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); + } + + UPB_DESC(FeatureSet*) resolved; + size_t child_size; + const char* child_bytes = + UPB_DESC(FeatureSet_serialize)(child, ctx->tmp_arena, &child_size); + if (!child_bytes) _upb_DefBuilder_OomErr(ctx); + + upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); + if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { + return resolved; + } + + upb_DecodeStatus dec_status = + upb_Decode(child_bytes, child_size, resolved, + UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); + if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); + + return resolved; +} + #include @@ -10739,7 +11242,8 @@ bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, // Must be last. struct upb_MessageDef { - const UPB_DESC(MessageOptions) * opts; + const UPB_DESC(MessageOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTable* layout; const upb_FileDef* file; const upb_MessageDef* containing_type; @@ -10777,6 +11281,9 @@ struct upb_MessageDef { bool in_message_set; bool is_sorted; upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; static void assign_msg_wellknowntype(upb_MessageDef* m) { @@ -11108,10 +11615,9 @@ void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - // TODO: Once editions is supported this should turn into a - // check on LEGACY_BEST_EFFORT if (strcmp(shortname, json_name) != 0 && - upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3 && + UPB_DESC(FeatureSet_json_format)(m->resolved_features) == + UPB_DESC(FeatureSet_ALLOW) && upb_strtable_lookup(&m->ntof, json_name, &v)) { _upb_DefBuilder_Errf( ctx, "duplicate json_name for (%s) with original field name (%s)", @@ -11228,7 +11734,8 @@ static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { uint64_t out = 0; - if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + if (UPB_DESC(FeatureSet_repeated_field_encoding(m->resolved_features)) == + UPB_DESC(FeatureSet_PACKED)) { out |= kUpb_MessageModifier_DefaultIsPacked; } @@ -11342,7 +11849,8 @@ static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, } static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(DescriptorProto) * msg_proto, + const UPB_DESC(DescriptorProto*) msg_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* containing_type, upb_MessageDef* m) { const UPB_DESC(OneofDescriptorProto)* const* oneofs; @@ -11354,6 +11862,10 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, size_t n_ext_range, n_res_range, n_res_name; upb_StringView name; + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MessageOptions_features)(m->opts)); + // Must happen before _upb_DefBuilder_Add() m->file = _upb_DefBuilder_File(ctx); @@ -11382,14 +11894,12 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); m->field_count = n_field; - m->fields = - _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, + m->full_name, m, &m->is_sorted); // Message Sets may not contain fields. if (UPB_UNLIKELY(UPB_DESC(MessageOptions_message_set_wire_format)(m->opts))) { @@ -11399,7 +11909,8 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, } m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, + m->resolved_features, m); m->res_range_count = n_res_range; m->res_ranges = @@ -11417,23 +11928,29 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto)* const* enums = UPB_DESC(DescriptorProto_enum_type)(msg_proto, &n_enum); m->nested_enum_count = n_enum; - m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + m->nested_enums = + _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); const UPB_DESC(FieldDescriptorProto)* const* exts = UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext); m->nested_ext_count = n_ext; - m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->full_name, m); + m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, + m->full_name, m); const UPB_DESC(DescriptorProto)* const* msgs = UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg); m->nested_msg_count = n_msg; - m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); + m->nested_msgs = + _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); } // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); const char* name = containing_type ? containing_type->full_name @@ -11441,7 +11958,8 @@ upb_MessageDef* _upb_MessageDefs_New( upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + create_msgdef(ctx, name, protos[i], parent_features, containing_type, + &m[i]); } return m; } @@ -11500,7 +12018,8 @@ upb_MessageReservedRange* _upb_MessageReservedRanges_New( // Must be last. struct upb_MethodDef { - const UPB_DESC(MethodOptions) * opts; + const UPB_DESC(MethodOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; upb_ServiceDef* service; const char* full_name; const upb_MessageDef* input_type; @@ -11553,8 +12072,14 @@ bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { } static void create_method(upb_DefBuilder* ctx, - const UPB_DESC(MethodDescriptorProto) * method_proto, + const UPB_DESC(MethodDescriptorProto*) method_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s, upb_MethodDef* m) { + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MethodOptions_features)(m->opts)); + upb_StringView name = UPB_DESC(MethodDescriptorProto_name)(method_proto); m->service = s; @@ -11572,18 +12097,17 @@ static void create_method(upb_DefBuilder* ctx, ctx, m->full_name, m->full_name, UPB_DESC(MethodDescriptorProto_output_type)(method_proto), UPB_DEFTYPE_MSG); - - UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, - method_proto); } // Allocate and initialize an array of |n| method defs belonging to |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s) { +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s) { upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); + create_method(ctx, protos[i], parent_features, s, &m[i]); m[i].index = i; } return m; @@ -11598,7 +12122,8 @@ upb_MethodDef* _upb_MethodDefs_New( // Must be last. struct upb_OneofDef { - const UPB_DESC(OneofOptions) * opts; + const UPB_DESC(OneofOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MessageDef* parent; const char* full_name; int field_count; @@ -11606,9 +12131,6 @@ struct upb_OneofDef { const upb_FieldDef** fields; upb_strtable ntof; // lookup a field by name upb_inttable itof; // lookup a field by number (index) -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { @@ -11742,9 +12264,15 @@ size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { } static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, - const UPB_DESC(OneofDescriptorProto) * oneof_proto, + const UPB_DESC(OneofDescriptorProto*) oneof_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_OneofDef* _o) { upb_OneofDef* o = (upb_OneofDef*)_o; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + o->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(OneofOptions_features)(o->opts)); + upb_StringView name = UPB_DESC(OneofDescriptorProto_name)(oneof_proto); o->parent = m; @@ -11753,8 +12281,6 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, o->field_count = 0; o->synthetic = false; - UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } @@ -11771,14 +12297,16 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, } // Allocate and initialize an array of |n| oneof defs. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m) { +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); + create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); } return o; } @@ -11788,12 +12316,16 @@ upb_OneofDef* _upb_OneofDefs_New( // Must be last. struct upb_ServiceDef { - const UPB_DESC(ServiceOptions) * opts; + const UPB_DESC(ServiceOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const char* full_name; upb_MethodDef* methods; int method_count; int index; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { @@ -11844,37 +12376,40 @@ const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, } static void create_service(upb_DefBuilder* ctx, - const UPB_DESC(ServiceDescriptorProto) * svc_proto, + const UPB_DESC(ServiceDescriptorProto*) svc_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s) { - upb_StringView name; - size_t n; + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); + s->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(ServiceOptions_features)(s->opts)); // Must happen before _upb_DefBuilder_Add() s->file = _upb_DefBuilder_File(ctx); - name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); + upb_StringView name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); const char* package = _upb_FileDef_RawPackage(s->file); s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); _upb_DefBuilder_Add(ctx, s->full_name, _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + size_t n; const UPB_DESC(MethodDescriptorProto)* const* methods = UPB_DESC(ServiceDescriptorProto_method)(svc_proto, &n); s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, - svc_proto); + s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); } -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos) { +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features) { _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); + create_service(ctx, protos[i], parent_features, &s[i]); s[i].index = i; } return s; @@ -14895,6 +15430,7 @@ const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag, #undef UPB_GNUC_MIN #undef UPB_DESCRIPTOR_UPB_H_FILENAME #undef UPB_DESC +#undef UPB_DESC_MINITABLE #undef UPB_IS_GOOGLE3 #undef UPB_ATOMIC #undef UPB_USE_C11_ATOMICS diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 53562dcd4f..88b8b2206d 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -318,8 +318,13 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE0) +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif #ifndef UPB_BASE_STATUS_H_ @@ -10156,6 +10161,9 @@ UPB_API void upb_DefPool_Free(upb_DefPool* s); UPB_API upb_DefPool* upb_DefPool_New(void); +UPB_API const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s); + UPB_API const upb_MessageDef* upb_DefPool_FindMessageByName( const upb_DefPool* s, const char* sym); @@ -10247,6 +10255,7 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const UPB_DESC(EnumOptions) * upb_EnumDef_Options(const upb_EnumDef* e); +const UPB_DESC(FeatureSet) * upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e); upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); @@ -10285,6 +10294,8 @@ UPB_API const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); UPB_API int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); const UPB_DESC(EnumValueOptions) * upb_EnumValueDef_Options(const upb_EnumValueDef* v); +const UPB_DESC(FeatureSet) * + upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e); #ifdef __cplusplus } /* extern "C" */ @@ -10311,6 +10322,8 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); const UPB_DESC(ExtensionRangeOptions) * upb_ExtensionRange_Options(const upb_ExtensionRange* r); +const UPB_DESC(FeatureSet) * + upb_ExtensionRange_ResolvedFeatures(const upb_ExtensionRange* e); #ifdef __cplusplus } /* extern "C" */ @@ -10372,6 +10385,8 @@ const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); UPB_API const char* upb_FieldDef_Name(const upb_FieldDef* f); UPB_API uint32_t upb_FieldDef_Number(const upb_FieldDef* f); const UPB_DESC(FieldOptions) * upb_FieldDef_Options(const upb_FieldDef* f); +const UPB_DESC(FeatureSet) * + upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f); UPB_API const upb_OneofDef* upb_FieldDef_RealContainingOneof( const upb_FieldDef* f); UPB_API upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); @@ -10400,6 +10415,7 @@ int upb_FileDef_DependencyCount(const upb_FileDef* f); bool upb_FileDef_HasOptions(const upb_FileDef* f); UPB_API const char* upb_FileDef_Name(const upb_FileDef* f); const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f); +const UPB_DESC(FeatureSet) * upb_FileDef_ResolvedFeatures(const upb_FileDef* f); const char* upb_FileDef_Package(const upb_FileDef* f); UPB_DESC(Edition) upb_FileDef_Edition(const upb_FileDef* f); UPB_API const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); @@ -10559,6 +10575,8 @@ int upb_MessageDef_RealOneofCount(const upb_MessageDef* m); const UPB_DESC(MessageOptions) * upb_MessageDef_Options(const upb_MessageDef* m); +const UPB_DESC(FeatureSet) * + upb_MessageDef_ResolvedFeatures(const upb_MessageDef* m); upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); @@ -10596,6 +10614,8 @@ int upb_MethodDef_Index(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); const char* upb_MethodDef_Name(const upb_MethodDef* m); const UPB_DESC(MethodOptions) * upb_MethodDef_Options(const upb_MethodDef* m); +const UPB_DESC(FeatureSet) * + upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); @@ -10636,7 +10656,9 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, uint32_t num); UPB_API const char* upb_OneofDef_Name(const upb_OneofDef* o); int upb_OneofDef_numfields(const upb_OneofDef* o); -const UPB_DESC(OneofOptions) * upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(OneofOptions*) upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(FeatureSet*) + upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o); #ifdef __cplusplus } /* extern "C" */ @@ -10668,6 +10690,8 @@ int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); const char* upb_ServiceDef_Name(const upb_ServiceDef* s); const UPB_DESC(ServiceOptions) * upb_ServiceDef_Options(const upb_ServiceDef* s); +const UPB_DESC(FeatureSet) * + upb_ServiceDef_ResolvedFeatures(const upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ @@ -12100,6 +12124,42 @@ UPB_INLINE const char* upb_WireReader_SkipValue( #endif // UPB_WIRE_READER_H_ +#ifndef UPB_MESSAGE_COPY_H_ +#define UPB_MESSAGE_COPY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Deep clones a message using the provided target arena. +upb_Message* upb_Message_DeepClone(const upb_Message* message, + const upb_MiniTable* mini_table, + upb_Arena* arena); + +// Deep clones array contents. +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena); + +// Deep clones map contents. +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena); + +// Deep copies the message from src to dst. +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COPY_H_ + // EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// #ifndef UPB_COLLECTIONS_INTERNAL_MAP_SORTER_H_ @@ -12506,6 +12566,10 @@ extern "C" { struct upb_DefBuilder { upb_DefPool* symtab; + upb_strtable feature_cache; // Caches features by identity. + UPB_DESC(FeatureSet*) legacy_features; // For computing legacy features. + char* tmp_buf; // Temporary buffer in tmp_arena. + size_t tmp_buf_size; // Size of temporary buffer. upb_FileDef* file; // File we are building. upb_Arena* arena; // Allocate defs here. upb_Arena* tmp_arena; // For temporary allocations. @@ -12598,6 +12662,25 @@ UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); } +// Returns true if the returned feature set is new and must be populated. +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set); + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit); + +UPB_INLINE const UPB_DESC(FeatureSet*) + _upb_DefBuilder_ResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child) { + return _upb_DefBuilder_DoResolveFeatures(ctx, parent, child, false); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -12620,10 +12703,11 @@ bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); // Allocate and initialize an array of |n| enum defs. -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ @@ -12647,7 +12731,8 @@ upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted); const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, @@ -12684,16 +12769,19 @@ void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, const upb_FieldDef* f); // Allocate and initialize an array of |n| extensions (field defs). -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m); +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m); // Allocate and initialize an array of |n| field defs. -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted); +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted); // Allocate and return a list of pointers to the |n| field defs in |ff|, // sorted by field number. @@ -12758,9 +12846,12 @@ void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ @@ -12782,9 +12873,11 @@ extern "C" { upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); // Allocate and initialize an array of |n| service defs. -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos); +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features); #ifdef __cplusplus } /* extern "C" */ @@ -12793,6 +12886,20 @@ upb_ServiceDef* _upb_ServiceDefs_New( #endif /* UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ */ +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "\n\021\022\014\010\001\020\002\030\002 \001(\0010\002\030\346\007\n\021\022\014\010\002\020\001\030\001 \002(\0010\001\030\347\007\n\021\022\014\010\001\020\001\030\001 \002(\0010\001\030\350\007 \346\007(\350\007" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + #ifndef UPB_REFLECTION_DESC_STATE_INTERNAL_H_ #define UPB_REFLECTION_DESC_STATE_INTERNAL_H_ @@ -12865,7 +12972,7 @@ upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, // Allocate and initialize an array of |n| reserved ranges owned by |e|. upb_EnumReservedRange* _upb_EnumReservedRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto_EnumReservedRange) * const* protos, + const UPB_DESC(EnumDescriptorProto_EnumReservedRange*) const* protos, const upb_EnumDef* e); #ifdef __cplusplus @@ -12913,8 +13020,8 @@ upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); // Allocate and initialize an array of |n| extension ranges owned by |m|. upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m); + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m); #ifdef __cplusplus } /* extern "C" */ @@ -12938,9 +13045,11 @@ void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, const upb_FieldDef* f, const char* name, size_t size); // Allocate and initialize an array of |n| oneof defs owned by |m|. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m); +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m); size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); @@ -13012,9 +13121,11 @@ extern "C" { upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); // Allocate and initialize an array of |n| method defs owned by |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s); +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ @@ -13219,6 +13330,7 @@ UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { #undef UPB_GNUC_MIN #undef UPB_DESCRIPTOR_UPB_H_FILENAME #undef UPB_DESC +#undef UPB_DESC_MINITABLE #undef UPB_IS_GOOGLE3 #undef UPB_ATOMIC #undef UPB_USE_C11_ATOMICS diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 8790a0e32d..332aaea4e5 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -319,8 +319,13 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE0) +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif @@ -5395,6 +5400,289 @@ bool upb_Message_IsExactlyEqual(const upb_Message* m1, const upb_Message* m2, } +#include +#include + + +// Must be last. + +static bool upb_MessageField_IsMap(const upb_MiniTableField* field) { + return upb_FieldMode_Get(field) == kUpb_FieldMode_Map; +} + +static upb_StringView upb_Clone_StringView(upb_StringView str, + upb_Arena* arena) { + if (str.size == 0) { + return upb_StringView_FromDataAndSize(NULL, 0); + } + void* cloned_data = upb_Arena_Malloc(arena, str.size); + upb_StringView cloned_str = + upb_StringView_FromDataAndSize(cloned_data, str.size); + memcpy(cloned_data, str.data, str.size); + return cloned_str; +} + +static bool upb_Clone_MessageValue(void* value, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + switch (value_type) { + case kUpb_CType_Bool: + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return true; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView source = *(upb_StringView*)value; + int size = source.size; + void* cloned_data = upb_Arena_Malloc(arena, size); + if (cloned_data == NULL) { + return false; + } + *(upb_StringView*)value = + upb_StringView_FromDataAndSize(cloned_data, size); + memcpy(cloned_data, source.data, size); + return true; + } break; + case kUpb_CType_Message: { + const upb_TaggedMessagePtr source = *(upb_TaggedMessagePtr*)value; + bool is_empty = upb_TaggedMessagePtr_IsEmpty(source); + if (is_empty) sub = &_kUpb_MiniTable_Empty; + UPB_ASSERT(source); + upb_Message* clone = upb_Message_DeepClone( + _upb_TaggedMessagePtr_GetMessage(source), sub, arena); + *(upb_TaggedMessagePtr*)value = + _upb_TaggedMessagePtr_Pack(clone, is_empty); + return clone != NULL; + } break; + } + UPB_UNREACHABLE(); +} + +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena) { + upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size); + if (cloned_map == NULL) { + return NULL; + } + upb_MessageValue key, val; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map, &key, &val, &iter)) { + const upb_MiniTableField* value_field = &map_entry_table->fields[1]; + const upb_MiniTable* value_sub = + (value_field->UPB_PRIVATE(submsg_index) != kUpb_NoSub) + ? upb_MiniTable_GetSubMessageTable(map_entry_table, value_field) + : NULL; + upb_CType value_field_type = upb_MiniTableField_CType(value_field); + if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) { + return NULL; + } + if (upb_Map_Insert(cloned_map, key, val, arena) == + kUpb_MapInsertStatus_OutOfMemory) { + return NULL; + } + } + return cloned_map; +} + +static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, + upb_Arena* arena) { + const upb_MiniTable* map_entry_table = + mini_table->subs[field->UPB_PRIVATE(submsg_index)].submsg; + UPB_ASSERT(map_entry_table); + + const upb_MiniTableField* key_field = &map_entry_table->fields[0]; + const upb_MiniTableField* value_field = &map_entry_table->fields[1]; + + upb_Map* cloned_map = upb_Map_DeepClone( + map, upb_MiniTableField_CType(key_field), + upb_MiniTableField_CType(value_field), map_entry_table, arena); + if (!cloned_map) { + return NULL; + } + _upb_Message_SetNonExtensionField(clone, field, &cloned_map); + return cloned_map; +} + +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + size_t size = array->size; + upb_Array* cloned_array = + _upb_Array_New(arena, size, _upb_Array_CTypeSizeLg2(value_type)); + if (!cloned_array) { + return NULL; + } + if (!_upb_Array_ResizeUninitialized(cloned_array, size, arena)) { + return NULL; + } + for (size_t i = 0; i < size; ++i) { + upb_MessageValue val = upb_Array_Get(array, i); + if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) { + return false; + } + upb_Array_Set(cloned_array, i, val); + } + return cloned_array; +} + +static bool upb_Message_Array_DeepClone(const upb_Array* array, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, upb_Arena* arena) { + _upb_MiniTableField_CheckIsArray(field); + upb_Array* cloned_array = upb_Array_DeepClone( + array, upb_MiniTableField_CType(field), + upb_MiniTableField_CType(field) == kUpb_CType_Message && + field->UPB_PRIVATE(submsg_index) != kUpb_NoSub + ? upb_MiniTable_GetSubMessageTable(mini_table, field) + : NULL, + arena); + + // Clear out upb_Array* due to parent memcpy. + _upb_Message_SetNonExtensionField(clone, field, &cloned_array); + return true; +} + +static bool upb_Clone_ExtensionValue( + const upb_MiniTableExtension* mini_table_ext, + const upb_Message_Extension* source, upb_Message_Extension* dest, + upb_Arena* arena) { + dest->data = source->data; + return upb_Clone_MessageValue( + &dest->data, upb_MiniTableField_CType(&mini_table_ext->field), + mini_table_ext->sub.submsg, arena); +} + +upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0); + // Only copy message area skipping upb_Message_Internal. + memcpy(dst, src, mini_table->size); + for (size_t i = 0; i < mini_table->field_count; ++i) { + const upb_MiniTableField* field = &mini_table->fields[i]; + if (!upb_IsRepeatedOrMap(field)) { + switch (upb_MiniTableField_CType(field)) { + case kUpb_CType_Message: { + upb_TaggedMessagePtr tagged = + upb_Message_GetTaggedMessagePtr(src, field, NULL); + const upb_Message* sub_message = + _upb_TaggedMessagePtr_GetMessage(tagged); + if (sub_message != NULL) { + // If the message is currently in an unlinked, "empty" state we keep + // it that way, because we don't want to deal with decode options, + // decode status, or possible parse failure here. + bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged); + const upb_MiniTable* sub_message_table = + is_empty ? &_kUpb_MiniTable_Empty + : upb_MiniTable_GetSubMessageTable(mini_table, field); + upb_Message* dst_sub_message = + upb_Message_DeepClone(sub_message, sub_message_table, arena); + if (dst_sub_message == NULL) { + return NULL; + } + _upb_Message_SetTaggedMessagePtr( + dst, mini_table, field, + _upb_TaggedMessagePtr_Pack(dst_sub_message, is_empty)); + } + } break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView str = upb_Message_GetString(src, field, empty_string); + if (str.size != 0) { + if (!upb_Message_SetString( + dst, field, upb_Clone_StringView(str, arena), arena)) { + return NULL; + } + } + } break; + default: + // Scalar, already copied. + break; + } + } else { + if (upb_MessageField_IsMap(field)) { + const upb_Map* map = upb_Message_GetMap(src, field); + if (map != NULL) { + if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) { + return NULL; + } + } + } else { + const upb_Array* array = upb_Message_GetArray(src, field); + if (array != NULL) { + if (!upb_Message_Array_DeepClone(array, mini_table, field, dst, + arena)) { + return NULL; + } + } + } + } + } + // Clone extensions. + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(src, &ext_count); + for (size_t i = 0; i < ext_count; ++i) { + const upb_Message_Extension* msg_ext = &ext[i]; + const upb_MiniTableField* field = &msg_ext->ext->field; + upb_Message_Extension* dst_ext = + _upb_Message_GetOrCreateExtension(dst, msg_ext->ext, arena); + if (!dst_ext) return NULL; + if (!upb_IsRepeatedOrMap(field)) { + if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) { + return NULL; + } + } else { + upb_Array* msg_array = (upb_Array*)msg_ext->data.ptr; + UPB_ASSERT(msg_array); + upb_Array* cloned_array = + upb_Array_DeepClone(msg_array, upb_MiniTableField_CType(field), + msg_ext->ext->sub.submsg, arena); + if (!cloned_array) { + return NULL; + } + dst_ext->data.ptr = (void*)cloned_array; + } + } + + // Clone unknowns. + size_t unknown_size = 0; + const char* ptr = upb_Message_GetUnknown(src, &unknown_size); + if (unknown_size != 0) { + UPB_ASSERT(ptr); + // Make a copy into destination arena. + if (!_upb_Message_AddUnknown(dst, ptr, unknown_size, arena)) { + return NULL; + } + } + return dst; +} + +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena) { + upb_Message_Clear(dst, mini_table); + return _upb_Message_Copy(dst, src, mini_table, arena) != NULL; +} + +// Deep clones a message using the provided target arena. +// +// Returns NULL on failure. +upb_Message* upb_Message_DeepClone(const upb_Message* message, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + upb_Message* clone = upb_Message_New(mini_table, arena); + return _upb_Message_Copy(clone, message, mini_table, arena); +} + + #include // Must be last. @@ -7483,6 +7771,7 @@ struct upb_DefPool { upb_strtable files; // file_name -> (upb_FileDef*) upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) upb_ExtensionRegistry* extreg; + const UPB_DESC(FeatureSetDefaults) * feature_set_defaults; upb_MiniTablePlatform platform; void* scratch_data; size_t scratch_size; @@ -7495,6 +7784,8 @@ void upb_DefPool_Free(upb_DefPool* s) { upb_gfree(s); } +static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; + upb_DefPool* upb_DefPool_New(void) { upb_DefPool* s = upb_gmalloc(sizeof(*s)); if (!s) return NULL; @@ -7514,6 +7805,10 @@ upb_DefPool* upb_DefPool_New(void) { if (!s->extreg) goto err; s->platform = kUpb_MiniTablePlatform_Native; + s->feature_set_defaults = UPB_DESC(FeatureSetDefaults_parse)( + serialized_defaults, sizeof(serialized_defaults) - 1, s->arena); + + if (!s->feature_set_defaults) goto err; return s; @@ -7522,6 +7817,11 @@ err: return NULL; } +const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s) { + return s->feature_set_defaults; +} + bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, const upb_FieldDef* f) { return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), @@ -7735,7 +8035,11 @@ static const upb_FileDef* upb_DefBuilder_AddFileToPool( remove_filedef(s, builder->file); builder->file = NULL; } - } else if (!builder->arena || !builder->tmp_arena) { + } else if (!builder->arena || !builder->tmp_arena || + !upb_strtable_init(&builder->feature_cache, 16, + builder->tmp_arena) || + !(builder->legacy_features = + UPB_DESC(FeatureSet_new)(builder->tmp_arena))) { _upb_DefBuilder_OomErr(builder); } else { _upb_FileDef_Create(builder, file_proto); @@ -7768,6 +8072,8 @@ static const upb_FileDef* _upb_DefPool_AddFile( upb_DefBuilder ctx = { .symtab = s, + .tmp_buf = NULL, + .tmp_buf_size = 0, .layout = layout, .platform = s->platform, .msg_count = 0, @@ -7950,7 +8256,8 @@ bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { // Must be last. struct upb_EnumDef { - const UPB_DESC(EnumOptions) * opts; + const UPB_DESC(EnumOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTableEnum* layout; // Only for proto2. const upb_FileDef* file; const upb_MessageDef* containing_type; // Could be merged with "file". @@ -7964,8 +8271,10 @@ struct upb_EnumDef { int res_range_count; int res_name_count; int32_t defaultval; - bool is_closed; bool is_sorted; // Whether all of the values are defined in ascending order. +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { @@ -8067,7 +8376,11 @@ const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { return _upb_EnumValueDef_At(e->values, i); } -bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { return e->is_closed; } +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + return UPB_DESC(FeatureSet_enum_type)(e->resolved_features) == + UPB_DESC(FeatureSet_CLOSED); +} bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, upb_StringView* out) { @@ -8136,6 +8449,7 @@ static upb_StringView* _upb_EnumReservedNames_New( static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto) * enum_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e) { const UPB_DESC(EnumValueDescriptorProto)* const* values; const UPB_DESC(EnumDescriptorProto_EnumReservedRange)* const* res_ranges; @@ -8143,6 +8457,10 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, upb_StringView name; size_t n_value, n_res_range, n_res_name; + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + e->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumOptions_features)(e->opts)); + // Must happen before _upb_DefBuilder_Add() e->file = _upb_DefBuilder_File(ctx); @@ -8152,9 +8470,6 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, e->full_name, _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); - e->is_closed = (!UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) && - (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2); - values = UPB_DESC(EnumDescriptorProto_value)(enum_proto, &n_value); bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); @@ -8165,8 +8480,8 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->defaultval = 0; e->value_count = n_value; - e->values = - _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); + e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, + e->resolved_features, e, &e->is_sorted); if (n_value == 0) { _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", @@ -8183,11 +8498,9 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->res_name_count = n_res_name; e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); - UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - upb_inttable_compact(&e->iton, ctx->arena); - if (e->is_closed) { + if (upb_EnumDef_IsClosed(e)) { if (ctx->layout) { UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); e->layout = ctx->layout->enums[ctx->enum_count++]; @@ -8199,10 +8512,11 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, } } -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); // If a containing type is defined then get the full name from that. @@ -8212,7 +8526,7 @@ upb_EnumDef* _upb_EnumDefs_New( upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); for (int i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); + create_enumdef(ctx, name, protos[i], parent_features, &e[i]); e[i].containing_type = containing_type; } return e; @@ -8271,14 +8585,20 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( } +#include + // Must be last. struct upb_EnumValueDef { - const UPB_DESC(EnumValueOptions) * opts; + const UPB_DESC(EnumValueOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_EnumDef* parent; const char* full_name; int32_t number; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { @@ -8335,9 +8655,15 @@ uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { } static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(EnumValueDescriptorProto) * + const UPB_DESC(EnumValueDescriptorProto*) val_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, upb_EnumValueDef* v) { + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + v->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts)); + upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto); v->parent = e; // Must happen prior to _upb_DefBuilder_Add() @@ -8346,17 +8672,32 @@ static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, v->full_name, _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); - UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, - val_proto); - bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); } +static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx, + const upb_EnumDef* e, + const upb_EnumValueDef* v, int n) { + if (upb_EnumDef_IsClosed(e) || n == 0 || v[0].number == 0) return; + + // When the special UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 is enabled, we have to + // exempt proto2 enums from this check, even when we are treating them as + // open. + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 && + upb_FileDef_Syntax(upb_EnumDef_File(e)) == kUpb_Syntax_Proto2) { + return; + } + + _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)", + upb_EnumDef_FullName(e)); +} + // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); @@ -8366,29 +8707,27 @@ upb_EnumValueDef* _upb_EnumValueDefs_New( *is_sorted = true; uint32_t previous = 0; for (int i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); const uint32_t current = v[i].number; if (previous > current) *is_sorted = false; previous = current; } - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - upb_EnumDef_FullName(e)); - } + _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n); return v; } +#include + // Must be last. struct upb_ExtensionRange { - const UPB_DESC(ExtensionRangeOptions) * opts; + const UPB_DESC(ExtensionRangeOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; int32_t start; int32_t end; }; @@ -8414,12 +8753,18 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m) { + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m) { upb_ExtensionRange* r = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); for (int i = 0; i < n; i++) { + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, + UPB_DESC(ExtensionRangeOptions_features)(r[i].opts)); + const int32_t start = UPB_DESC(DescriptorProto_ExtensionRange_start)(protos[i]); const int32_t end = UPB_DESC(DescriptorProto_ExtensionRange_end)(protos[i]); @@ -8439,8 +8784,6 @@ upb_ExtensionRange* _upb_ExtensionRanges_New( r[i].start = start; r[i].end = end; - UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, protos[i]); } return r; @@ -8462,7 +8805,8 @@ typedef struct { } str_t; struct upb_FieldDef { - const UPB_DESC(FieldOptions) * opts; + const UPB_DESC(FieldOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const upb_MessageDef* msgdef; const char* full_name; @@ -8492,13 +8836,9 @@ struct upb_FieldDef { bool has_json_name; bool has_presence; bool is_extension; - bool is_packed; bool is_proto3_optional; upb_FieldType type_; upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { @@ -8567,7 +8907,9 @@ bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { } bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { - return _upb_FieldDef_IsPackable(f) && f->is_packed; + return _upb_FieldDef_IsPackable(f) && + UPB_DESC(FeatureSet_repeated_field_encoding(f->resolved_features)) == + UPB_DESC(FeatureSet_PACKED); } const char* upb_FieldDef_Name(const upb_FieldDef* f) { @@ -8680,44 +9022,21 @@ bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } -// begin:google_only -// static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { -// #if defined(UPB_BOOTSTRAP_STAGE0) -// return true; -// #else -// return UPB_DESC(FieldOptions_enforce_utf8)(f->opts); -// #endif -// } -// end:google_only - -// begin:github_only -static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { - return true; -} -// end:github_only - bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; - return upb_FileDef_Syntax(upb_FieldDef_File(f)) == kUpb_Syntax_Proto3 - ? _upb_FieldDef_EnforceUtf8Option(f) - : false; + return UPB_DESC(FeatureSet_utf8_validation(f->resolved_features)) == + UPB_DESC(FeatureSet_VERIFY); } uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; - switch (f->label_) { - case kUpb_Label_Optional: - if (!upb_FieldDef_HasPresence(f)) { - out |= kUpb_FieldModifier_IsProto3Singular; - } - break; - case kUpb_Label_Repeated: - out |= kUpb_FieldModifier_IsRepeated; - break; - case kUpb_Label_Required: - out |= kUpb_FieldModifier_IsRequired; - break; + if (upb_FieldDef_IsRepeated(f)) { + out |= kUpb_FieldModifier_IsRepeated; + } else if (upb_FieldDef_IsRequired(f)) { + out |= kUpb_FieldModifier_IsRequired; + } else if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; } if (_upb_FieldDef_IsClosedEnum(f)) { @@ -8757,7 +9076,8 @@ bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { } bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; + return UPB_DESC(FeatureSet_field_presence)(f->resolved_features) == + UPB_DESC(FeatureSet_LEGACY_REQUIRED); } bool upb_FieldDef_IsString(const upb_FieldDef* f) { @@ -8981,19 +9301,63 @@ static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { } } +static bool _upb_FieldDef_InferLegacyFeatures( + upb_DefBuilder* ctx, upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto*) proto, + const UPB_DESC(FieldOptions*) options, upb_Syntax syntax, + UPB_DESC(FeatureSet*) features) { + bool ret = false; + + if (UPB_DESC(FieldDescriptorProto_label)(proto) == kUpb_Label_Required) { + if (syntax == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + int val = UPB_DESC(FeatureSet_LEGACY_REQUIRED); + UPB_DESC(FeatureSet_set_field_presence(features, val)); + ret = true; + } + + if (UPB_DESC(FieldDescriptorProto_type)(proto) == kUpb_FieldType_Group) { + int val = UPB_DESC(FeatureSet_DELIMITED); + UPB_DESC(FeatureSet_set_message_encoding(features, val)); + ret = true; + } + + if (UPB_DESC(FieldOptions_has_packed)(options)) { + int val = UPB_DESC(FieldOptions_packed)(options) + ? UPB_DESC(FeatureSet_PACKED) + : UPB_DESC(FeatureSet_EXPANDED); + UPB_DESC(FeatureSet_set_repeated_field_encoding(features, val)); + ret = true; + } + +// begin:google_only +// #ifndef UPB_BOOTSTRAP_STAGE0 +// if (syntax == kUpb_Syntax_Proto3 && +// UPB_DESC(FieldOptions_has_enforce_utf8)(options) && +// !UPB_DESC(FieldOptions_enforce_utf8)(options)) { +// int val = UPB_DESC(FeatureSet_UNVERIFIED); +// UPB_DESC(FeatureSet_set_utf8_validation(features, val)); +// ret = true; +// } +// #endif +// // clang-format off +// end:google_only + // clang-format on + + return ret; +} + static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { // Must happen before _upb_DefBuilder_Add() f->file = _upb_DefBuilder_File(ctx); - if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto); - f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto); f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto); @@ -9002,6 +9366,29 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, f->msgdef = m; f->scope.oneof = NULL; + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + upb_Syntax syntax = upb_FileDef_Syntax(f->file); + const UPB_DESC(FeatureSet*) unresolved_features = + UPB_DESC(FieldOptions_features)(f->opts); + bool implicit = false; + + if (syntax != kUpb_Syntax_Editions) { + upb_Message_Clear(ctx->legacy_features, UPB_DESC_MINITABLE(FeatureSet)); + if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, syntax, + ctx->legacy_features)) { + implicit = true; + unresolved_features = ctx->legacy_features; + } + } + + f->resolved_features = _upb_DefBuilder_DoResolveFeatures( + ctx, parent_features, unresolved_features, implicit); + + if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto); if (f->has_json_name) { const upb_StringView sv = @@ -9057,12 +9444,6 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, * to the field_proto until later when we can properly resolve it. */ f->sub.unresolved = field_proto; - if (f->label_ == kUpb_Label_Required && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } - if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { int oneof_index = UPB_DESC(FieldDescriptorProto_oneof_index)(field_proto); @@ -9086,27 +9467,21 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); } - UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (UPB_DESC(FieldOptions_has_packed)(f->opts)) { - f->is_packed = UPB_DESC(FieldOptions_packed)(f->opts); - } else { - f->is_packed = upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; - } - f->has_presence = (!upb_FieldDef_IsRepeated(f)) && (f->type_ == kUpb_FieldType_Message || f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || - (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto2)); + UPB_DESC(FeatureSet_field_presence)(f->resolved_features) != + UPB_DESC(FeatureSet_IMPLICIT)); } static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = true; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", @@ -9123,11 +9498,13 @@ static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, } static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) + parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = false; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (!UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { if (f->is_proto3_optional) { @@ -9141,10 +9518,11 @@ static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, _upb_MessageDef_InsertField(ctx, m, f); } -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m) { +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -9152,17 +9530,19 @@ upb_FieldDef* _upb_Extensions_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; } return defs; } -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted) { +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -9171,7 +9551,7 @@ upb_FieldDef* _upb_FieldDefs_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; if (!ctx->layout) { // Speculate that the def fields are sorted. We will always sort the @@ -9375,11 +9755,14 @@ void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, } +#include + // Must be last. struct upb_FileDef { - const UPB_DESC(FileOptions) * opts; + const UPB_DESC(FileOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const char* name; const char* package; UPB_DESC(Edition) edition; @@ -9409,6 +9792,11 @@ const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f) { return f->opts; } +const UPB_DESC(FeatureSet) * + upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { + return f->resolved_features; +} + bool upb_FileDef_HasOptions(const upb_FileDef* f) { return f->opts != (void*)kUpbDefOptDefault; } @@ -9525,6 +9913,34 @@ static int count_exts_in_msg(const UPB_DESC(DescriptorProto) * msg_proto) { return ext_count; } +const UPB_DESC(FeatureSet*) + _upb_FileDef_FindEdition(upb_DefBuilder* ctx, int edition) { + const UPB_DESC(FeatureSetDefaults)* defaults = + upb_DefPool_FeatureSetDefaults(ctx->symtab); + + int min = UPB_DESC(FeatureSetDefaults_minimum_edition)(defaults); + int max = UPB_DESC(FeatureSetDefaults_maximum_edition)(defaults); + if (edition < min || edition > max) { + _upb_DefBuilder_Errf(ctx, + "Edition %d is outside the supported range [%d, %d] " + "given in the defaults", + edition, min, max); + } + + size_t n; + const UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault)* const* d = + UPB_DESC(FeatureSetDefaults_defaults)(defaults, &n); + const UPB_DESC(FeatureSet)* ret = NULL; + for (size_t i = 0; i < n; i++) { + if (UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_edition)(d[i]) > + edition) { + break; + } + ret = UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_features)(d[i]); + } + return ret; +} + // Allocate and initialize one file def, and add it to the context object. void _upb_FileDef_Create(upb_DefBuilder* ctx, const UPB_DESC(FileDescriptorProto) * file_proto) { @@ -9593,21 +10009,33 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, if (streql_view(syntax, "proto2")) { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } else if (streql_view(syntax, "proto3")) { file->syntax = kUpb_Syntax_Proto3; + file->edition = UPB_DESC(EDITION_PROTO3); } else if (streql_view(syntax, "editions")) { file->syntax = kUpb_Syntax_Editions; + file->edition = UPB_DESC(FileDescriptorProto_edition)(file_proto); } else { _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", UPB_STRINGVIEW_ARGS(syntax)); } } else { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } // Read options. UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + // Resolve features. + const UPB_DESC(FeatureSet*) edition_defaults = + _upb_FileDef_FindEdition(ctx, file->edition); + const UPB_DESC(FeatureSet*) unresolved = + UPB_DESC(FileOptions_features)(file->opts); + file->resolved_features = + _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); + // Verify dependencies. strs = UPB_DESC(FileDescriptorProto_dependency)(file_proto, &n); file->dep_count = n; @@ -9653,22 +10081,26 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, // Create enums. enums = UPB_DESC(FileDescriptorProto_enum_type)(file_proto, &n); file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); + file->top_lvl_enums = + _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); // Create extensions. exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n); file->top_lvl_ext_count = n; - file->top_lvl_exts = _upb_Extensions_New(ctx, n, exts, file->package, NULL); + file->top_lvl_exts = _upb_Extensions_New( + ctx, n, exts, file->resolved_features, file->package, NULL); // Create messages. msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n); file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); + file->top_lvl_msgs = + _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); // Create services. services = UPB_DESC(FileDescriptorProto_service)(file_proto, &n); file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); + file->services = + _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); // Now that all names are in the table, build layouts and resolve refs. @@ -10031,6 +10463,77 @@ void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, UPB_ASSERT(false); } +upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key) { + size_t need = key.size + sizeof(void*); + if (ctx->tmp_buf_size < need) { + ctx->tmp_buf_size = UPB_MAX(64, upb_Log2Ceiling(need)); + ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); + if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); + } + + memcpy(ctx->tmp_buf, &parent, sizeof(void*)); + memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); + return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); +} + +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set) { + upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); + upb_value v; + if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { + *set = upb_value_getptr(v); + return false; + } + + *set = + upb_Message_DeepClone(parent, UPB_DESC_MINITABLE(FeatureSet), ctx->arena); + if (!*set) _upb_DefBuilder_OomErr(ctx); + + v = upb_value_ptr(*set); + if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, + ctx->tmp_arena)) { + _upb_DefBuilder_OomErr(ctx); + } + + return true; +} + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit) { + assert(parent); + if (!child) return parent; + + if (child && !is_implicit && + upb_FileDef_Syntax(ctx->file) != kUpb_Syntax_Editions) { + _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); + } + + UPB_DESC(FeatureSet*) resolved; + size_t child_size; + const char* child_bytes = + UPB_DESC(FeatureSet_serialize)(child, ctx->tmp_arena, &child_size); + if (!child_bytes) _upb_DefBuilder_OomErr(ctx); + + upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); + if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { + return resolved; + } + + upb_DecodeStatus dec_status = + upb_Decode(child_bytes, child_size, resolved, + UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); + if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); + + return resolved; +} + #include @@ -10254,7 +10757,8 @@ bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, // Must be last. struct upb_MessageDef { - const UPB_DESC(MessageOptions) * opts; + const UPB_DESC(MessageOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTable* layout; const upb_FileDef* file; const upb_MessageDef* containing_type; @@ -10292,6 +10796,9 @@ struct upb_MessageDef { bool in_message_set; bool is_sorted; upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; static void assign_msg_wellknowntype(upb_MessageDef* m) { @@ -10623,10 +11130,9 @@ void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - // TODO: Once editions is supported this should turn into a - // check on LEGACY_BEST_EFFORT if (strcmp(shortname, json_name) != 0 && - upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3 && + UPB_DESC(FeatureSet_json_format)(m->resolved_features) == + UPB_DESC(FeatureSet_ALLOW) && upb_strtable_lookup(&m->ntof, json_name, &v)) { _upb_DefBuilder_Errf( ctx, "duplicate json_name for (%s) with original field name (%s)", @@ -10743,7 +11249,8 @@ static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { uint64_t out = 0; - if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + if (UPB_DESC(FeatureSet_repeated_field_encoding(m->resolved_features)) == + UPB_DESC(FeatureSet_PACKED)) { out |= kUpb_MessageModifier_DefaultIsPacked; } @@ -10857,7 +11364,8 @@ static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, } static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(DescriptorProto) * msg_proto, + const UPB_DESC(DescriptorProto*) msg_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* containing_type, upb_MessageDef* m) { const UPB_DESC(OneofDescriptorProto)* const* oneofs; @@ -10869,6 +11377,10 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, size_t n_ext_range, n_res_range, n_res_name; upb_StringView name; + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MessageOptions_features)(m->opts)); + // Must happen before _upb_DefBuilder_Add() m->file = _upb_DefBuilder_File(ctx); @@ -10897,14 +11409,12 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); m->field_count = n_field; - m->fields = - _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, + m->full_name, m, &m->is_sorted); // Message Sets may not contain fields. if (UPB_UNLIKELY(UPB_DESC(MessageOptions_message_set_wire_format)(m->opts))) { @@ -10914,7 +11424,8 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, } m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, + m->resolved_features, m); m->res_range_count = n_res_range; m->res_ranges = @@ -10932,23 +11443,29 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto)* const* enums = UPB_DESC(DescriptorProto_enum_type)(msg_proto, &n_enum); m->nested_enum_count = n_enum; - m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + m->nested_enums = + _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); const UPB_DESC(FieldDescriptorProto)* const* exts = UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext); m->nested_ext_count = n_ext; - m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->full_name, m); + m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, + m->full_name, m); const UPB_DESC(DescriptorProto)* const* msgs = UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg); m->nested_msg_count = n_msg; - m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); + m->nested_msgs = + _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); } // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); const char* name = containing_type ? containing_type->full_name @@ -10956,7 +11473,8 @@ upb_MessageDef* _upb_MessageDefs_New( upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + create_msgdef(ctx, name, protos[i], parent_features, containing_type, + &m[i]); } return m; } @@ -11015,7 +11533,8 @@ upb_MessageReservedRange* _upb_MessageReservedRanges_New( // Must be last. struct upb_MethodDef { - const UPB_DESC(MethodOptions) * opts; + const UPB_DESC(MethodOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; upb_ServiceDef* service; const char* full_name; const upb_MessageDef* input_type; @@ -11068,8 +11587,14 @@ bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { } static void create_method(upb_DefBuilder* ctx, - const UPB_DESC(MethodDescriptorProto) * method_proto, + const UPB_DESC(MethodDescriptorProto*) method_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s, upb_MethodDef* m) { + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MethodOptions_features)(m->opts)); + upb_StringView name = UPB_DESC(MethodDescriptorProto_name)(method_proto); m->service = s; @@ -11087,18 +11612,17 @@ static void create_method(upb_DefBuilder* ctx, ctx, m->full_name, m->full_name, UPB_DESC(MethodDescriptorProto_output_type)(method_proto), UPB_DEFTYPE_MSG); - - UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, - method_proto); } // Allocate and initialize an array of |n| method defs belonging to |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s) { +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s) { upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); + create_method(ctx, protos[i], parent_features, s, &m[i]); m[i].index = i; } return m; @@ -11113,7 +11637,8 @@ upb_MethodDef* _upb_MethodDefs_New( // Must be last. struct upb_OneofDef { - const UPB_DESC(OneofOptions) * opts; + const UPB_DESC(OneofOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MessageDef* parent; const char* full_name; int field_count; @@ -11121,9 +11646,6 @@ struct upb_OneofDef { const upb_FieldDef** fields; upb_strtable ntof; // lookup a field by name upb_inttable itof; // lookup a field by number (index) -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { @@ -11257,9 +11779,15 @@ size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { } static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, - const UPB_DESC(OneofDescriptorProto) * oneof_proto, + const UPB_DESC(OneofDescriptorProto*) oneof_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_OneofDef* _o) { upb_OneofDef* o = (upb_OneofDef*)_o; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + o->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(OneofOptions_features)(o->opts)); + upb_StringView name = UPB_DESC(OneofDescriptorProto_name)(oneof_proto); o->parent = m; @@ -11268,8 +11796,6 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, o->field_count = 0; o->synthetic = false; - UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } @@ -11286,14 +11812,16 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, } // Allocate and initialize an array of |n| oneof defs. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m) { +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); + create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); } return o; } @@ -11303,12 +11831,16 @@ upb_OneofDef* _upb_OneofDefs_New( // Must be last. struct upb_ServiceDef { - const UPB_DESC(ServiceOptions) * opts; + const UPB_DESC(ServiceOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const char* full_name; upb_MethodDef* methods; int method_count; int index; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { @@ -11359,37 +11891,40 @@ const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, } static void create_service(upb_DefBuilder* ctx, - const UPB_DESC(ServiceDescriptorProto) * svc_proto, + const UPB_DESC(ServiceDescriptorProto*) svc_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s) { - upb_StringView name; - size_t n; + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); + s->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(ServiceOptions_features)(s->opts)); // Must happen before _upb_DefBuilder_Add() s->file = _upb_DefBuilder_File(ctx); - name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); + upb_StringView name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); const char* package = _upb_FileDef_RawPackage(s->file); s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); _upb_DefBuilder_Add(ctx, s->full_name, _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + size_t n; const UPB_DESC(MethodDescriptorProto)* const* methods = UPB_DESC(ServiceDescriptorProto_method)(svc_proto, &n); s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, - svc_proto); + s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); } -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos) { +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features) { _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); + create_service(ctx, protos[i], parent_features, &s[i]); s[i].index = i; } return s; @@ -14410,6 +14945,7 @@ const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag, #undef UPB_GNUC_MIN #undef UPB_DESCRIPTOR_UPB_H_FILENAME #undef UPB_DESC +#undef UPB_DESC_MINITABLE #undef UPB_IS_GOOGLE3 #undef UPB_ATOMIC #undef UPB_USE_C11_ATOMICS diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 9393812f7e..ba67dfa2ea 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -320,8 +320,13 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE0) +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif #ifndef UPB_BASE_STATUS_H_ @@ -10660,6 +10665,9 @@ UPB_API void upb_DefPool_Free(upb_DefPool* s); UPB_API upb_DefPool* upb_DefPool_New(void); +UPB_API const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s); + UPB_API const upb_MessageDef* upb_DefPool_FindMessageByName( const upb_DefPool* s, const char* sym); @@ -10751,6 +10759,7 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const UPB_DESC(EnumOptions) * upb_EnumDef_Options(const upb_EnumDef* e); +const UPB_DESC(FeatureSet) * upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e); upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); @@ -10789,6 +10798,8 @@ UPB_API const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); UPB_API int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); const UPB_DESC(EnumValueOptions) * upb_EnumValueDef_Options(const upb_EnumValueDef* v); +const UPB_DESC(FeatureSet) * + upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e); #ifdef __cplusplus } /* extern "C" */ @@ -10815,6 +10826,8 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); const UPB_DESC(ExtensionRangeOptions) * upb_ExtensionRange_Options(const upb_ExtensionRange* r); +const UPB_DESC(FeatureSet) * + upb_ExtensionRange_ResolvedFeatures(const upb_ExtensionRange* e); #ifdef __cplusplus } /* extern "C" */ @@ -10876,6 +10889,8 @@ const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); UPB_API const char* upb_FieldDef_Name(const upb_FieldDef* f); UPB_API uint32_t upb_FieldDef_Number(const upb_FieldDef* f); const UPB_DESC(FieldOptions) * upb_FieldDef_Options(const upb_FieldDef* f); +const UPB_DESC(FeatureSet) * + upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f); UPB_API const upb_OneofDef* upb_FieldDef_RealContainingOneof( const upb_FieldDef* f); UPB_API upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); @@ -10904,6 +10919,7 @@ int upb_FileDef_DependencyCount(const upb_FileDef* f); bool upb_FileDef_HasOptions(const upb_FileDef* f); UPB_API const char* upb_FileDef_Name(const upb_FileDef* f); const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f); +const UPB_DESC(FeatureSet) * upb_FileDef_ResolvedFeatures(const upb_FileDef* f); const char* upb_FileDef_Package(const upb_FileDef* f); UPB_DESC(Edition) upb_FileDef_Edition(const upb_FileDef* f); UPB_API const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); @@ -11063,6 +11079,8 @@ int upb_MessageDef_RealOneofCount(const upb_MessageDef* m); const UPB_DESC(MessageOptions) * upb_MessageDef_Options(const upb_MessageDef* m); +const UPB_DESC(FeatureSet) * + upb_MessageDef_ResolvedFeatures(const upb_MessageDef* m); upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); @@ -11100,6 +11118,8 @@ int upb_MethodDef_Index(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); const char* upb_MethodDef_Name(const upb_MethodDef* m); const UPB_DESC(MethodOptions) * upb_MethodDef_Options(const upb_MethodDef* m); +const UPB_DESC(FeatureSet) * + upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); @@ -11140,7 +11160,9 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, uint32_t num); UPB_API const char* upb_OneofDef_Name(const upb_OneofDef* o); int upb_OneofDef_numfields(const upb_OneofDef* o); -const UPB_DESC(OneofOptions) * upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(OneofOptions*) upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(FeatureSet*) + upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o); #ifdef __cplusplus } /* extern "C" */ @@ -11172,6 +11194,8 @@ int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); const char* upb_ServiceDef_Name(const upb_ServiceDef* s); const UPB_DESC(ServiceOptions) * upb_ServiceDef_Options(const upb_ServiceDef* s); +const UPB_DESC(FeatureSet) * + upb_ServiceDef_ResolvedFeatures(const upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ @@ -11872,6 +11896,42 @@ UPB_INLINE const char* upb_WireReader_SkipValue( #endif // UPB_WIRE_READER_H_ +#ifndef UPB_MESSAGE_COPY_H_ +#define UPB_MESSAGE_COPY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Deep clones a message using the provided target arena. +upb_Message* upb_Message_DeepClone(const upb_Message* message, + const upb_MiniTable* mini_table, + upb_Arena* arena); + +// Deep clones array contents. +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena); + +// Deep clones map contents. +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena); + +// Deep copies the message from src to dst. +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COPY_H_ + // EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// #ifndef UPB_COLLECTIONS_INTERNAL_MAP_SORTER_H_ @@ -12325,6 +12385,10 @@ extern "C" { struct upb_DefBuilder { upb_DefPool* symtab; + upb_strtable feature_cache; // Caches features by identity. + UPB_DESC(FeatureSet*) legacy_features; // For computing legacy features. + char* tmp_buf; // Temporary buffer in tmp_arena. + size_t tmp_buf_size; // Size of temporary buffer. upb_FileDef* file; // File we are building. upb_Arena* arena; // Allocate defs here. upb_Arena* tmp_arena; // For temporary allocations. @@ -12417,6 +12481,25 @@ UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); } +// Returns true if the returned feature set is new and must be populated. +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set); + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit); + +UPB_INLINE const UPB_DESC(FeatureSet*) + _upb_DefBuilder_ResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child) { + return _upb_DefBuilder_DoResolveFeatures(ctx, parent, child, false); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -12439,10 +12522,11 @@ bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); // Allocate and initialize an array of |n| enum defs. -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ @@ -12466,7 +12550,8 @@ upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted); const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, @@ -12503,16 +12588,19 @@ void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, const upb_FieldDef* f); // Allocate and initialize an array of |n| extensions (field defs). -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m); +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m); // Allocate and initialize an array of |n| field defs. -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted); +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted); // Allocate and return a list of pointers to the |n| field defs in |ff|, // sorted by field number. @@ -12577,9 +12665,12 @@ void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ @@ -12601,9 +12692,11 @@ extern "C" { upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); // Allocate and initialize an array of |n| service defs. -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos); +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features); #ifdef __cplusplus } /* extern "C" */ @@ -12612,6 +12705,20 @@ upb_ServiceDef* _upb_ServiceDefs_New( #endif /* UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ */ +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "\n\021\022\014\010\001\020\002\030\002 \001(\0010\002\030\346\007\n\021\022\014\010\002\020\001\030\001 \002(\0010\001\030\347\007\n\021\022\014\010\001\020\001\030\001 \002(\0010\001\030\350\007 \346\007(\350\007" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + #ifndef UPB_REFLECTION_DESC_STATE_INTERNAL_H_ #define UPB_REFLECTION_DESC_STATE_INTERNAL_H_ @@ -12684,7 +12791,7 @@ upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, // Allocate and initialize an array of |n| reserved ranges owned by |e|. upb_EnumReservedRange* _upb_EnumReservedRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto_EnumReservedRange) * const* protos, + const UPB_DESC(EnumDescriptorProto_EnumReservedRange*) const* protos, const upb_EnumDef* e); #ifdef __cplusplus @@ -12732,8 +12839,8 @@ upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); // Allocate and initialize an array of |n| extension ranges owned by |m|. upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m); + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m); #ifdef __cplusplus } /* extern "C" */ @@ -12757,9 +12864,11 @@ void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, const upb_FieldDef* f, const char* name, size_t size); // Allocate and initialize an array of |n| oneof defs owned by |m|. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m); +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m); size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); @@ -12831,9 +12940,11 @@ extern "C" { upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); // Allocate and initialize an array of |n| method defs owned by |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s); +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ @@ -13038,6 +13149,7 @@ UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { #undef UPB_GNUC_MIN #undef UPB_DESCRIPTOR_UPB_H_FILENAME #undef UPB_DESC +#undef UPB_DESC_MINITABLE #undef UPB_IS_GOOGLE3 #undef UPB_ATOMIC #undef UPB_USE_C11_ATOMICS