diff --git a/src/google/protobuf/compiler/BUILD.bazel b/src/google/protobuf/compiler/BUILD.bazel index f98c31785bec..45afef2a933a 100644 --- a/src/google/protobuf/compiler/BUILD.bazel +++ b/src/google/protobuf/compiler/BUILD.bazel @@ -164,6 +164,7 @@ cc_binary( copts = COPTS, visibility = [ "//src/google/protobuf:__subpackages__", + "//upb:__subpackages__", ], deps = [ ":command_line_interface", diff --git a/upb/BUILD b/upb/BUILD index 1e52a8092b14..ff5d6defc704 100644 --- a/upb/BUILD +++ b/upb/BUILD @@ -406,6 +406,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", @@ -456,6 +457,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", @@ -506,6 +508,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", diff --git a/upb/port/def.inc b/upb/port/def.inc index f32082138463..aa335c8c869b 100644 --- a/upb/port/def.inc +++ b/upb/port/def.inc @@ -323,6 +323,11 @@ 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 diff --git a/upb/port/undef.inc b/upb/port/undef.inc index eb0e1654f8fb..5a1429e34c49 100644 --- a/upb/port/undef.inc +++ b/upb/port/undef.inc @@ -49,6 +49,7 @@ #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/upb/reflection/BUILD b/upb/reflection/BUILD index bf0c0e4dbeb7..f6ea369d0661 100644 --- a/upb/reflection/BUILD +++ b/upb/reflection/BUILD @@ -5,6 +5,15 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd +load( + "//upb/cmake:build_defs.bzl", + "staleness_test", +) +load( + "//src/google/protobuf/editions:defaults.bzl", + "compile_edition_defaults", + "embed_edition_defaults", +) load("//bazel:build_defs.bzl", "UPB_DEFAULT_COPTS") load("//bazel:upb_minitable_proto_library.bzl", "upb_minitable_proto_library") load("//bazel:upb_proto_library.bzl", "upb_proto_reflection_library") @@ -108,6 +117,7 @@ bootstrap_cc_library( "internal/method_def.h", "internal/oneof_def.h", "internal/service_def.h", + "internal/upb_edition_defaults.h", "message.h", "message.hpp", "message_def.h", @@ -125,11 +135,13 @@ bootstrap_cc_library( "//upb:mem", "//upb:message", "//upb:message_accessors", + "//upb:message_copy", "//upb:message_value", "//upb:mini_descriptor", "//upb:mini_descriptor_internal", "//upb:mini_table", "//upb:port", + "//upb/base:internal", ], ) @@ -171,6 +183,30 @@ cc_test( ], ) +compile_edition_defaults( + name = "upb_edition_defaults", + srcs = [ + "//:descriptor_proto", + ], + maximum_edition = "2023", + minimum_edition = "PROTO2", +) + +embed_edition_defaults( + name = "embedded_upb_edition_defaults_generate", + defaults = "upb_edition_defaults", + output = "generated/internal/upb_edition_defaults.h", + placeholder = "DEFAULTS_VALUE", + template = "internal/upb_edition_defaults.h.template", +) + +staleness_test( + name = "bootstrap_upb_defaults_staleness_test", + outs = ["internal/upb_edition_defaults.h"], + generated_pattern = "generated/%s", + target_files = ["internal/upb_edition_defaults.h"], +) + # begin:github_only filegroup( name = "source_files", diff --git a/upb/reflection/def_pool.c b/upb/reflection/def_pool.c index 90d3beadf57e..88e42ded15b1 100644 --- a/upb/reflection/def_pool.c +++ b/upb/reflection/def_pool.c @@ -17,6 +17,7 @@ #include "upb/reflection/internal/file_def.h" #include "upb/reflection/internal/message_def.h" #include "upb/reflection/internal/service_def.h" +#include "upb/reflection/internal/upb_edition_defaults.h" // Must be last. #include "upb/port/def.inc" @@ -27,6 +28,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; @@ -39,6 +41,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; @@ -58,6 +62,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; @@ -66,6 +74,11 @@ upb_DefPool* upb_DefPool_New(void) { 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), @@ -279,7 +292,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); @@ -312,6 +329,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, diff --git a/upb/reflection/def_pool.h b/upb/reflection/def_pool.h index f21a0dbd2db7..63cce8a08074 100644 --- a/upb/reflection/def_pool.h +++ b/upb/reflection/def_pool.h @@ -26,6 +26,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); diff --git a/upb/reflection/enum_def.c b/upb/reflection/enum_def.c index 97fc63e9acea..8ba894f21d66 100644 --- a/upb/reflection/enum_def.c +++ b/upb/reflection/enum_def.c @@ -23,7 +23,8 @@ #include "upb/port/def.inc" 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". @@ -37,8 +38,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) { @@ -140,7 +143,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) { @@ -209,6 +216,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; @@ -216,6 +224,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); @@ -225,9 +237,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); @@ -238,8 +247,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)", @@ -256,11 +265,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++]; @@ -272,10 +279,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. @@ -285,7 +293,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; diff --git a/upb/reflection/enum_def.h b/upb/reflection/enum_def.h index 6f406f54bb07..a81ce5fd1171 100644 --- a/upb/reflection/enum_def.h +++ b/upb/reflection/enum_def.h @@ -40,6 +40,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); diff --git a/upb/reflection/enum_value_def.c b/upb/reflection/enum_value_def.c index d06c9331075c..d250daade6e5 100644 --- a/upb/reflection/enum_value_def.c +++ b/upb/reflection/enum_value_def.c @@ -7,19 +7,27 @@ #include "upb/reflection/internal/enum_value_def.h" +#include + #include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/file_def.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/internal/enum_def.h" -#include "upb/reflection/internal/file_def.h" // Must be last. #include "upb/port/def.inc" 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) { @@ -76,9 +84,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() @@ -87,17 +101,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)); @@ -107,19 +136,14 @@ 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; } diff --git a/upb/reflection/enum_value_def.h b/upb/reflection/enum_value_def.h index e95232847a16..4fbbade19d02 100644 --- a/upb/reflection/enum_value_def.h +++ b/upb/reflection/enum_value_def.h @@ -27,6 +27,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" */ diff --git a/upb/reflection/extension_range.c b/upb/reflection/extension_range.c index b088ba92ede6..658a0a41e82f 100644 --- a/upb/reflection/extension_range.c +++ b/upb/reflection/extension_range.c @@ -7,6 +7,9 @@ #include "upb/reflection/internal/extension_range.h" +#include + +#include "upb/reflection/extension_range.h" #include "upb/reflection/field_def.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/message_def.h" @@ -16,6 +19,7 @@ struct upb_ExtensionRange { const UPB_DESC(ExtensionRangeOptions) * opts; + const UPB_DESC(FeatureSet) * resolved_features; int32_t start; int32_t end; }; @@ -41,12 +45,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]); @@ -66,8 +76,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; diff --git a/upb/reflection/extension_range.h b/upb/reflection/extension_range.h index 7c3e19f005b1..3ddd5340e740 100644 --- a/upb/reflection/extension_range.h +++ b/upb/reflection/extension_range.h @@ -25,6 +25,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" */ diff --git a/upb/reflection/field_def.c b/upb/reflection/field_def.c index 537d05ef85a7..5b67e209ccb3 100644 --- a/upb/reflection/field_def.c +++ b/upb/reflection/field_def.c @@ -12,6 +12,7 @@ #include #include "upb/base/descriptor_constants.h" +#include "upb/message/accessors.h" #include "upb/mini_descriptor/decode.h" #include "upb/mini_descriptor/internal/modifiers.h" #include "upb/reflection/def.h" @@ -35,7 +36,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; @@ -65,13 +67,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) { @@ -140,7 +138,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) { @@ -253,44 +253,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)) { @@ -330,7 +307,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) { @@ -554,19 +532,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); @@ -575,6 +597,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 = @@ -630,12 +675,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); @@ -659,27 +698,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)", @@ -696,11 +729,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) { @@ -714,10 +749,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); @@ -725,17 +761,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); @@ -744,7 +782,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 diff --git a/upb/reflection/field_def.h b/upb/reflection/field_def.h index b3305bc1f29d..35c3e702ede5 100644 --- a/upb/reflection/field_def.h +++ b/upb/reflection/field_def.h @@ -61,6 +61,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); diff --git a/upb/reflection/file_def.c b/upb/reflection/file_def.c index bd4b254cac43..abdbd3523e84 100644 --- a/upb/reflection/file_def.c +++ b/upb/reflection/file_def.c @@ -7,6 +7,8 @@ #include "upb/reflection/internal/file_def.h" +#include + #include "upb/reflection/def_pool.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/internal/enum_def.h" @@ -19,7 +21,8 @@ #include "upb/port/def.inc" 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; @@ -49,6 +52,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; } @@ -165,6 +173,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) { @@ -233,21 +269,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; @@ -293,22 +341,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. diff --git a/upb/reflection/file_def.h b/upb/reflection/file_def.h index f338c25f92e5..912d0081d986 100644 --- a/upb/reflection/file_def.h +++ b/upb/reflection/file_def.h @@ -24,6 +24,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); diff --git a/upb/reflection/internal/def_builder.c b/upb/reflection/internal/def_builder.c index 2ab16f27deef..c0b5b65da7bb 100644 --- a/upb/reflection/internal/def_builder.c +++ b/upb/reflection/internal/def_builder.c @@ -9,9 +9,12 @@ #include +#include "upb/base/internal/log2.h" +#include "upb/message/copy.h" #include "upb/reflection/def_pool.h" #include "upb/reflection/def_type.h" #include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" #include "upb/reflection/internal/strdup2.h" // Must be last. @@ -337,3 +340,74 @@ void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, // We should never reach this point. 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 + 8, 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; +} diff --git a/upb/reflection/internal/def_builder.h b/upb/reflection/internal/def_builder.h index 584553214dea..b9a0bff5f8f7 100644 --- a/upb/reflection/internal/def_builder.h +++ b/upb/reflection/internal/def_builder.h @@ -36,6 +36,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. @@ -128,6 +132,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 diff --git a/upb/reflection/internal/enum_def.h b/upb/reflection/internal/enum_def.h index 8f6b22011203..d8912a08c4d4 100644 --- a/upb/reflection/internal/enum_def.h +++ b/upb/reflection/internal/enum_def.h @@ -22,10 +22,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" */ diff --git a/upb/reflection/internal/enum_reserved_range.h b/upb/reflection/internal/enum_reserved_range.h index fe30604a1a86..6b988ee2458d 100644 --- a/upb/reflection/internal/enum_reserved_range.h +++ b/upb/reflection/internal/enum_reserved_range.h @@ -23,7 +23,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 diff --git a/upb/reflection/internal/enum_value_def.h b/upb/reflection/internal/enum_value_def.h index 2484567febac..e75e48a6e25a 100644 --- a/upb/reflection/internal/enum_value_def.h +++ b/upb/reflection/internal/enum_value_def.h @@ -22,7 +22,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, diff --git a/upb/reflection/internal/extension_range.h b/upb/reflection/internal/extension_range.h index 09901b41ff81..2432701c5f9c 100644 --- a/upb/reflection/internal/extension_range.h +++ b/upb/reflection/internal/extension_range.h @@ -22,8 +22,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" */ diff --git a/upb/reflection/internal/field_def.h b/upb/reflection/internal/field_def.h index 838f3b607028..f41a8226a637 100644 --- a/upb/reflection/internal/field_def.h +++ b/upb/reflection/internal/field_def.h @@ -31,16 +31,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. diff --git a/upb/reflection/internal/message_def.h b/upb/reflection/internal/message_def.h index 6cc9686a7415..a8bcec244f48 100644 --- a/upb/reflection/internal/message_def.h +++ b/upb/reflection/internal/message_def.h @@ -30,9 +30,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" */ diff --git a/upb/reflection/internal/method_def.h b/upb/reflection/internal/method_def.h index a7e8ef8a37a1..b2b628d64227 100644 --- a/upb/reflection/internal/method_def.h +++ b/upb/reflection/internal/method_def.h @@ -20,9 +20,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" */ diff --git a/upb/reflection/internal/oneof_def.h b/upb/reflection/internal/oneof_def.h index 9cd6713efd32..7d803d592cd8 100644 --- a/upb/reflection/internal/oneof_def.h +++ b/upb/reflection/internal/oneof_def.h @@ -22,9 +22,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); diff --git a/upb/reflection/internal/service_def.h b/upb/reflection/internal/service_def.h index 2845b879070c..b95b53b842f7 100644 --- a/upb/reflection/internal/service_def.h +++ b/upb/reflection/internal/service_def.h @@ -20,9 +20,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" */ diff --git a/upb/reflection/internal/upb_edition_defaults.h b/upb/reflection/internal/upb_edition_defaults.h new file mode 100644 index 000000000000..587d3b13d184 --- /dev/null +++ b/upb/reflection/internal/upb_edition_defaults.h @@ -0,0 +1,20 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#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_ diff --git a/upb/reflection/internal/upb_edition_defaults.h.template b/upb/reflection/internal/upb_edition_defaults.h.template new file mode 100644 index 000000000000..58ff7f1eb39f --- /dev/null +++ b/upb/reflection/internal/upb_edition_defaults.h.template @@ -0,0 +1,20 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#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 "DEFAULTS_VALUE" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ diff --git a/upb/reflection/message_def.c b/upb/reflection/message_def.c index 9e55d612a4ca..96037d18633d 100644 --- a/upb/reflection/message_def.c +++ b/upb/reflection/message_def.c @@ -28,7 +28,8 @@ #include "upb/port/def.inc" 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; @@ -66,6 +67,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) { @@ -397,10 +401,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)", @@ -517,7 +520,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; } @@ -631,7 +635,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; @@ -643,6 +648,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); @@ -671,14 +680,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))) { @@ -688,7 +695,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 = @@ -706,23 +714,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 @@ -730,7 +744,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; } diff --git a/upb/reflection/message_def.h b/upb/reflection/message_def.h index a5c85efe23c6..1a92ed4349a2 100644 --- a/upb/reflection/message_def.h +++ b/upb/reflection/message_def.h @@ -136,6 +136,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); diff --git a/upb/reflection/method_def.c b/upb/reflection/method_def.c index 049ef4a81d17..ee4e06efff8a 100644 --- a/upb/reflection/method_def.c +++ b/upb/reflection/method_def.c @@ -15,7 +15,8 @@ #include "upb/port/def.inc" 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; @@ -68,8 +69,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; @@ -87,18 +94,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; diff --git a/upb/reflection/method_def.h b/upb/reflection/method_def.h index 64b88a66832e..4abfb69e0f60 100644 --- a/upb/reflection/method_def.h +++ b/upb/reflection/method_def.h @@ -26,6 +26,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); diff --git a/upb/reflection/oneof_def.c b/upb/reflection/oneof_def.c index 869ca16b96c4..04ce27dc4456 100644 --- a/upb/reflection/oneof_def.c +++ b/upb/reflection/oneof_def.c @@ -23,6 +23,7 @@ struct upb_OneofDef { const UPB_DESC(OneofOptions) * opts; + const UPB_DESC(FeatureSet) * resolved_features; const upb_MessageDef* parent; const char* full_name; int field_count; @@ -30,9 +31,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) { @@ -166,9 +164,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; @@ -177,8 +181,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); } @@ -195,14 +197,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; } diff --git a/upb/reflection/oneof_def.h b/upb/reflection/oneof_def.h index 38c7a7002f32..1a62f3dc8b7b 100644 --- a/upb/reflection/oneof_def.h +++ b/upb/reflection/oneof_def.h @@ -36,7 +36,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" */ diff --git a/upb/reflection/service_def.c b/upb/reflection/service_def.c index 7a0cbc7a09b8..f1d1eee0c0a9 100644 --- a/upb/reflection/service_def.c +++ b/upb/reflection/service_def.c @@ -17,11 +17,15 @@ struct upb_ServiceDef { 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) { @@ -72,37 +76,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; diff --git a/upb/reflection/service_def.h b/upb/reflection/service_def.h index 98cd993b4d72..781932e176fc 100644 --- a/upb/reflection/service_def.h +++ b/upb/reflection/service_def.h @@ -30,6 +30,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" */ diff --git a/upb/util/required_fields.c b/upb/util/required_fields.c index c6616ecdd3f7..b93adc0d9958 100644 --- a/upb/util/required_fields.c +++ b/upb/util/required_fields.c @@ -196,7 +196,7 @@ static void upb_util_FindUnsetInMessage(upb_FindContext* ctx, // Iterate over all fields to see if any required fields are missing. for (int i = 0, n = upb_MessageDef_FieldCount(m); i < n; i++) { const upb_FieldDef* f = upb_MessageDef_Field(m, i); - if (upb_FieldDef_Label(f) != kUpb_Label_Required) continue; + if (!upb_FieldDef_IsRequired(f)) continue; if (!msg || !upb_Message_HasFieldByDef(msg, f)) { // A required field is missing.