diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 2ad232f4f4..28266153d5 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -3774,7 +3774,8 @@ bool FieldDescriptor::requires_utf8_validation() const { bool FieldDescriptor::has_presence() const { if (is_repeated()) return false; - return cpp_type() == CPPTYPE_MESSAGE || containing_oneof() || + return cpp_type() == CPPTYPE_MESSAGE || is_extension() || + containing_oneof() || features().field_presence() != FeatureSet::IMPLICIT; } diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 71aa90318a..617f729110 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -7634,6 +7634,41 @@ TEST_F(FeaturesTest, Proto3Extensions) { R"pb([bar_ext] { baz: 1 })pb")); } +TEST_F(FeaturesTest, Proto3ExtensionPresence) { + BuildDescriptorMessagesInTestPool(); + const FileDescriptor* file = BuildFile(R"pb( + name: "foo.proto" + syntax: "proto3" + dependency: "google/protobuf/descriptor.proto" + extension { + name: "singular_ext" + number: 1001 + label: LABEL_OPTIONAL + type: TYPE_STRING + extendee: ".google.protobuf.FileOptions" + } + extension { + name: "singular_proto3_optional_ext" + number: 1002 + label: LABEL_OPTIONAL + type: TYPE_STRING + extendee: ".google.protobuf.FileOptions" + proto3_optional: true + } + extension { + name: "repeated_ext" + number: 1003 + label: LABEL_REPEATED + type: TYPE_STRING + extendee: ".google.protobuf.FileOptions" + } + )pb"); + + EXPECT_TRUE(file->extension(0)->has_presence()); + EXPECT_TRUE(file->extension(1)->has_presence()); + EXPECT_FALSE(file->extension(2)->has_presence()); +} + TEST_F(FeaturesTest, Edition2023Defaults) { FileDescriptorProto file_proto = ParseTextOrDie(R"pb( name: "foo.proto"