First implementation of C# nullable reference types enablement using the current (unreleased) edition.

PiperOrigin-RevId: 897682871
diff --git a/MODULE.bazel b/MODULE.bazel
index 04a8b56..8848636 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -24,7 +24,7 @@
 #endif // PROTO2_OPENSOURCE
 # protoc dependencies
 bazel_dep(name = "abseil-cpp", version = "20250512.1")
-bazel_dep(name = "rules_cc", version = "0.0.17")
+bazel_dep(name = "rules_cc", version = "0.2.18")
 bazel_dep(name = "zlib", version = "1.3.1.bcr.5")
 #ifndef PROTO2_OPENSOURCE
 # LINT.ThenChange(//depot/google3/third_party/protobuf/compiler/notices.h)
diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec
index 02e3a62..2cb5ec0 100644
--- a/csharp/Google.Protobuf.Tools.nuspec
+++ b/csharp/Google.Protobuf.Tools.nuspec
@@ -23,8 +23,8 @@
     <file src="protoc/linux_aarch64/protoc" target="tools/linux_aarch64/protoc"/>
     <file src="protoc/macosx_x64/protoc" target="tools/macosx_x64/protoc"/>
     <!--
-      - Include the protos for the well-known types in a directory where protoc will
-      - find them by default.
+      - Include the protos for the well-known types and language-specific editions features in a
+      - directory where protoc will find them by default.
       -->
     <file src="src/google/protobuf/any.proto" target="tools/include/google/protobuf"/>
     <file src="src/google/protobuf/api.proto" target="tools/include/google/protobuf"/>
@@ -37,9 +37,11 @@
     <file src="src/google/protobuf/timestamp.proto" target="tools/include/google/protobuf"/>
     <file src="src/google/protobuf/type.proto" target="tools/include/google/protobuf"/>
     <file src="src/google/protobuf/wrappers.proto" target="tools/include/google/protobuf"/>
+    <file src="csharp/google/protobuf/c_sharp_features.proto" target="tools/include/google/protobuf"/>
     <!--
       - Include the protos for the well-known types again in their old location,
-      - for backward compatibility.
+      - for backward compatibility. This does not include features files, as those have never been
+      - in tools/google/protobuf directory.
       -->
     <file src="src/google/protobuf/any.proto" target="tools/google/protobuf"/>
     <file src="src/google/protobuf/api.proto" target="tools/google/protobuf"/>
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
index a2e9b3a..615e45c 100755
--- a/csharp/generate_protos.sh
+++ b/csharp/generate_protos.sh
@@ -67,6 +67,7 @@
     conformance/test_protos/test_messages_edition2023.proto \
     conformance/test_protos/test_messages_edition_unstable.proto \
     csharp/protos/map_unittest_proto3.proto \
+    csharp/protos/nrt.proto \
     csharp/protos/unittest_issues.proto \
     csharp/protos/unittest_custom_options_proto3.proto \
     csharp/protos/unittest_proto3.proto \
diff --git a/csharp/google/protobuf/c_sharp_features.proto b/csharp/google/protobuf/c_sharp_features.proto
index eb9af73..f26300f 100644
--- a/csharp/google/protobuf/c_sharp_features.proto
+++ b/csharp/google/protobuf/c_sharp_features.proto
@@ -20,4 +20,17 @@
 }
 
 message CSharpFeatures {
+  // Whether the generated files should have nullable reference type annotations.
+  // When enabled, the generated C# code includes `#nullable enable annotations`
+  // and annotates message-typed properties and certain parameters with `?`.
+  optional bool nullable_reference_types = 1 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_MESSAGE,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_UNSTABLE,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "false" }
+  ];
 }
diff --git a/csharp/protos/nrt.proto b/csharp/protos/nrt.proto
new file mode 100644
index 0000000..00b7f22
--- /dev/null
+++ b/csharp/protos/nrt.proto
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2026 Google Inc.  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
+
+edition = "UNSTABLE";
+
+package protobuf_editionstesting;
+
+import "csharp/protos/unittest_import_proto3.proto";
+import "csharp/protos/unittest.proto";
+
+import option "csharp/google/protobuf/c_sharp_features.proto";
+option features.(pb.csharp).nullable_reference_types = true;
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+// This file is used for testing NRT support in C#, both in terms of
+// manual inspection of the generated code, and checking that it compiles.
+// It exercises many aspects of protobuf, but does not attempt to be
+// comprehensive in checking (for example) all primitive numeric types.
+
+extend protobuf_unittest_proto2.TestAllExtensions {
+  int32 int32_ext = 1234567;
+  string string_ext = 1234568;
+  protobuf_unittest_proto2.TestAllExtensions message_ext = 1234569;
+}
+
+message NrtMessage {
+  protobuf_unittest_import.ImportMessage proto3_import_message = 1;
+  OtherNrtMessage other_message = 2;
+  string text = 3;
+  int32 integer = 4;
+  bytes blob = 5;
+  NrtEnum enum_field = 6;
+
+  message NestedMessage {
+    string text = 1;
+  }
+}
+
+message OtherNrtMessage {
+  string text = 1;
+}
+
+message ExtendableNrtMessage {
+  extensions 65536 to max;
+}
+
+enum NrtEnum {
+  NRT_ENUM_UNSPECIFIED = 0;
+  FOO = 1;
+  BAR = 2;
+}
diff --git a/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs b/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs
index f15da61..0b29472 100644
--- a/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs
+++ b/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs
@@ -10,6 +10,7 @@
 using NUnit.Framework;
 using System.Diagnostics;
 using System;
+using System.Linq;
 using System.Reflection;
 using System.IO;
 
@@ -43,11 +44,13 @@
             // "XYZ is obsolete: 'Types with embedded references are not supported in this version of your compiler.'"
             // We build the code with GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE to avoid the use of ref struct in the generated code.
             var compatibilityFlag = "-define:GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE";
-            var sources = "*.cs";  // the generated sources from the TestProtos project
+            var sources = Directory.GetFiles(testProtosProjectDir, "*.cs")
+                .Select(Path.GetFileName)
+                .Except(new[] { "Nrt.pb.cs" }); // We don't expect the NRT code to compile with the old compiler.
             // We suppress CS1691, which flags a warning for the generated line of
             // #pragma warning disable 1591, 0612, 3021, 8981
             // because CS8981 is unknown to this version of the compiler.
-            var args = $"-langversion:3 -nologo -nowarn:1691 -target:library {compatibilityFlag} -reference:{testProtosOutputDir}\\Google.Protobuf.dll -out:{testProtosOutputDir}\\TestProtos.RefStructCompatibilityTest.OldCompiler.dll {sources}";
+            var args = $"-langversion:3 -nologo -nowarn:1691 -target:library {compatibilityFlag} -reference:{testProtosOutputDir}\\Google.Protobuf.dll -out:{testProtosOutputDir}\\TestProtos.RefStructCompatibilityTest.OldCompiler.dll {string.Join(" ", sources)}";
             RunOldCsharpCompilerAndCheckSuccess(args, testProtosProjectDir);
         }
 
diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel
index ab848dc..464407c 100644
--- a/examples/MODULE.bazel
+++ b/examples/MODULE.bazel
@@ -19,7 +19,7 @@
 )
 
 bazel_dep(name = "bazel_skylib", version = "1.7.1")
-bazel_dep(name = "rules_cc", version = "0.0.17")
+bazel_dep(name = "rules_cc", version = "0.2.18")
 bazel_dep(name = "rules_java", version = "8.6.1")
 bazel_dep(name = "rules_pkg", version = "1.0.1")
 bazel_dep(name = "rules_python", version = "1.6.0")
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index c590bc9..72785fb 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -103,9 +103,9 @@
     if not native.existing_rule("rules_cc"):
         http_archive(
             name = "rules_cc",
-            urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.16/rules_cc-0.0.16.tar.gz"],
-            sha256 = "bbf1ae2f83305b7053b11e4467d317a7ba3517a12cef608543c1b1c5bf48a4df",
-            strip_prefix = "rules_cc-0.0.16",
+            urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz"],
+            sha256 = "b8b918a85f9144c01f6cfe0f45e4f2838c7413961a8ff23bc0c6cdf8bb07a3b6",
+            strip_prefix = "rules_cc-0.1.5",
         )
 
     if not native.existing_rule("rules_java"):
diff --git a/src/google/protobuf/compiler/csharp/BUILD.bazel b/src/google/protobuf/compiler/csharp/BUILD.bazel
index 6bb9d6a..0560cde 100644
--- a/src/google/protobuf/compiler/csharp/BUILD.bazel
+++ b/src/google/protobuf/compiler/csharp/BUILD.bazel
@@ -69,6 +69,7 @@
         "//src/google/protobuf/compiler:__pkg__",
     ],
     deps = [
+        ":csharp_features_bootstrap",
         ":names",
         "//src/google/protobuf",
         "//src/google/protobuf:port",
@@ -126,6 +127,22 @@
     ],
 )
 
+cc_library(
+    name = "csharp_features_bootstrap",
+    srcs = ["c_sharp_features.pb.cc"],
+    hdrs = ["c_sharp_features.pb.h"],
+    copts = COPTS,
+    strip_include_prefix = "/src",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//src/google/protobuf",
+        "//src/google/protobuf:arena",
+        "//src/google/protobuf:port",
+        "//src/google/protobuf:protobuf_lite",
+        "//src/google/protobuf/io",
+    ],
+)
+
 ################################################################################
 # Distribution packaging
 ################################################################################
diff --git a/src/google/protobuf/compiler/csharp/c_sharp_features.pb.cc b/src/google/protobuf/compiler/csharp/c_sharp_features.pb.cc
new file mode 100755
index 0000000..6dd7005
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/c_sharp_features.pb.cc
@@ -0,0 +1,430 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// NO CHECKED-IN PROTOBUF GENCODE
+// source: google/protobuf/compiler/csharp/c_sharp_features.proto
+// Protobuf C++ Version: 7.36.0-dev
+
+#include "google/protobuf/compiler/csharp/c_sharp_features.pb.h"
+
+#include <algorithm>
+#include <type_traits>
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/generated_message_tctable_impl.h"
+#include "google/protobuf/internal_visibility.h"
+#include "google/protobuf/extension_set.h"
+#include "google/protobuf/generated_message_util.h"
+#include "google/protobuf/wire_format_lite.h"
+#include "google/protobuf/descriptor.h"
+#include "google/protobuf/generated_message_reflection.h"
+#include "google/protobuf/reflection_ops.h"
+#include "google/protobuf/wire_format.h"
+// @@protoc_insertion_point(includes)
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+PROTOBUF_PRAGMA_INIT_SEG
+namespace _pb = ::google::protobuf;
+namespace _pbi = ::google::protobuf::internal;
+namespace _fl = ::google::protobuf::internal::field_layout;
+#ifdef PROTOBUF_MESSAGE_GLOBALS
+namespace {
+PROTOBUF_CONSTINIT ::google::protobuf::internal::ReflectionData
+    file_reflection_data[] = {
+        // ::pb::CSharpFeatures
+        {&::_pbi::kDescriptorMethods, &::descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto, /* tracker*/ nullptr,},
+};
+}  // namespace
+#endif
+namespace pb {
+class CSharpFeatures::_Internal {
+ public:
+  using HasBits = decltype(::std::declval<CSharpFeatures>()._impl_._has_bits_);
+  static constexpr ::int32_t kHasBitsOffset =
+      8 * PROTOBUF_FIELD_OFFSET(CSharpFeatures, _impl_._has_bits_);
+};
+
+constexpr CSharpFeatures::ParseTableT_ CSharpFeatures::InternalGenerateParseTable_(const ::_pbi::ClassData* class_data) {
+  return ParseTableT_{
+    {
+      PROTOBUF_FIELD_OFFSET(CSharpFeatures, _impl_._has_bits_),
+      0, // no _extensions_
+      1, 0,  // max_field_number, fast_idx_mask
+      offsetof(ParseTableT_, field_lookup_table),
+      4294967294,  // skipmap
+      offsetof(ParseTableT_, field_entries),
+      1,  // num_field_entries
+      0,  // num_aux_entries
+      offsetof(ParseTableT_, field_names),  // no aux_entries
+      class_data,
+      nullptr,  // post_loop_handler
+      ::_pbi::TcParser::GenericFallback,  // fallback
+      #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
+      ::_pbi::TcParser::GetTable<::pb::CSharpFeatures>(),  // to_prefetch
+      #endif  // PROTOBUF_PREFETCH_PARSE_TABLE
+    }, {{
+      // optional bool nullable_reference_types = 1 [retention = RETENTION_RUNTIME, targets = TARGET_TYPE_FIELD, targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_FILE, edition_defaults = {
+      {::_pbi::TcParser::SingularVarintNoZag1<bool, offsetof(CSharpFeatures, _impl_.nullable_reference_types_), 0>(),
+       {8, 0, 0,
+        PROTOBUF_FIELD_OFFSET(CSharpFeatures, _impl_.nullable_reference_types_)}},
+    }}, {{
+      65535, 65535
+    }}, {{
+      // optional bool nullable_reference_types = 1 [retention = RETENTION_RUNTIME, targets = TARGET_TYPE_FIELD, targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_FILE, edition_defaults = {
+      {PROTOBUF_FIELD_OFFSET(CSharpFeatures, _impl_.nullable_reference_types_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kBool)},
+    }},
+    // no aux_entries
+    {{
+    }},
+  };
+}
+
+
+inline constexpr CSharpFeatures::Impl_::Impl_(
+    [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility,
+    ::_pbi::ConstantInitialized) noexcept
+      : nullable_reference_types_{false} {}
+
+template <typename>
+constexpr CSharpFeatures::CSharpFeatures(::_pbi::ConstantInitialized,
+                       const ::_pbi::ClassData* PROTOBUF_NONNULL class_data)
+    : ::google::protobuf::Message(
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+          class_data
+#endif  // PROTOBUF_CUSTOM_VTABLE
+          ),
+      _impl_(internal_visibility(), ::_pbi::ConstantInitialized()) {
+}
+inline void* PROTOBUF_NONNULL CSharpFeatures::PlacementNew_(
+    const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem,
+    ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) {
+  return ::new (mem) CSharpFeatures(arena);
+}
+constexpr auto CSharpFeatures::InternalNewImpl_() {
+  return ::google::protobuf::internal::MessageCreator::ZeroInit(sizeof(CSharpFeatures), alignof(CSharpFeatures));
+}
+constexpr auto CSharpFeatures::InternalGenerateClassData_(
+    const MessageLite& prototype,
+    const ::google::protobuf::internal::TcParseTableBase* tc_table) {
+  return ::google::protobuf::internal::ClassDataFull{
+      ::google::protobuf::internal::ClassData{
+          &prototype,
+#ifndef PROTOBUF_MESSAGE_GLOBALS
+          &_table_.header,
+#else
+          tc_table,
+#endif
+          nullptr,  // IsInitialized
+          &CSharpFeatures::MergeImpl,
+          ::google::protobuf::Message::GetNewImpl<CSharpFeatures>(),
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+          &CSharpFeatures::SharedDtor,
+          ::google::protobuf::Message::GetClearImpl<CSharpFeatures>(), &CSharpFeatures::ByteSizeLong,
+              &CSharpFeatures::_InternalSerialize,
+#endif  // PROTOBUF_CUSTOM_VTABLE
+          PROTOBUF_FIELD_OFFSET(CSharpFeatures, _impl_._cached_size_),
+          false,
+      },
+#ifdef PROTOBUF_MESSAGE_GLOBALS
+      &file_reflection_data[0],
+#else   // !PROTOBUF_MESSAGE_GLOBALS
+      &::_pbi::kDescriptorMethods,
+      &descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto,
+      nullptr,  // tracker
+#endif  // PROTOBUF_MESSAGE_GLOBALS
+  };
+}
+struct CSharpFeaturesGlobalsTypeInternal : ::_pbi::MessageGlobalsBase {
+  constexpr CSharpFeaturesGlobalsTypeInternal()
+      :
+#ifndef PROTOBUF_MESSAGE_GLOBALS
+        _default(::_pbi::ConstantInitialized{},
+                 CSharpFeatures_class_data_.base())
+#else   // !PROTOBUF_MESSAGE_GLOBALS
+        MessageGlobalsBase(CSharpFeatures::InternalGenerateClassData_(
+            _default, &CSharpFeatures_globals_._table.header)),
+        _default(::_pbi::ConstantInitialized{}, GetClassData()),
+        _table(::_pbi::PrivateAccess::GenerateParseTable<CSharpFeatures>(
+            GetClassData()))
+#endif  // PROTOBUF_MESSAGE_GLOBALS
+  {
+  }
+  ~CSharpFeaturesGlobalsTypeInternal() {}
+  union {
+    alignas(::_pbi::kMaxMessageAlignment) CSharpFeatures _default;
+  };
+#ifdef PROTOBUF_MESSAGE_GLOBALS
+  decltype(::_pbi::PrivateAccess::GenerateParseTable<CSharpFeatures>(
+      ::std::declval<const ::_pbi::ClassData*>())) _table;
+#endif
+};
+#ifdef PROTOBUF_MESSAGE_GLOBALS
+static_assert(PROTOBUF_FIELD_OFFSET(CSharpFeaturesGlobalsTypeInternal, _default) ==
+              ::_pbi::MessageGlobalsBase::OffsetToDefault());
+#endif  // PROTOBUF_MESSAGE_GLOBALS
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOC_EXPORT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PROTOBUF_MESSAGE_GLOBALS_CONST CSharpFeaturesGlobalsTypeInternal CSharpFeatures_globals_
+        PROTOBUF_MESSAGE_GLOBALS_SECTION(.data.rel.ro);
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+namespace {
+const ::_pbi::ClassData* CSharpFeatures_get_class_data() {
+#ifdef PROTOBUF_MESSAGE_GLOBALS
+  return CSharpFeatures_globals_.GetClassData();
+#else
+  return CSharpFeatures_class_data_.base();
+#endif  // PROTOBUF_MESSAGE_GLOBALS
+}
+}  // namespace
+#endif  // PROTOBUF_CUSTOM_VTABLE
+}  // namespace pb
+static constexpr const ::_pb::EnumDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE
+    file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto = nullptr;
+static constexpr const ::_pb::ServiceDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE
+    file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto = nullptr;
+const ::uint32_t
+    TableStruct_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto::offsets[] ABSL_ATTRIBUTE_SECTION_VARIABLE(
+        protodesc_cold) = {
+        0x081, // bitmap
+        PROTOBUF_FIELD_OFFSET(::pb::CSharpFeatures, _impl_._has_bits_),
+        4, // hasbit index offset
+        PROTOBUF_FIELD_OFFSET(::pb::CSharpFeatures, _impl_.nullable_reference_types_),
+        0,
+};
+
+static const ::_pbi::MigrationSchema
+    schemas[] ABSL_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+        {0, sizeof(::pb::CSharpFeatures)},
+};
+static const ::_pbi::MessageGlobalsBase* PROTOBUF_NONNULL const
+    file_message_globals[] = {
+        &::pb::CSharpFeatures_globals_,
+};
+const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto[] ABSL_ATTRIBUTE_SECTION_VARIABLE(
+    protodesc_cold) = {
+    "\n6google/protobuf/compiler/csharp/c_shar"
+    "p_features.proto\022\002pb\032 google/protobuf/de"
+    "scriptor.proto\"S\n\016CSharpFeatures\022A\n\030null"
+    "able_reference_types\030\001 \001(\010B\037\210\001\001\230\001\004\230\001\003\230\001\001"
+    "\242\001\n\022\005false\030\204\007\262\001\003\010\217N:@\n\006csharp\022\033.google.p"
+    "rotobuf.FeatureSet\030\354\007 \001(\0132\022.pb.CSharpFea"
+    "turesB9B\030CSharpFeaturesOuterClassP\001\252\002\032Go"
+    "ogle.Protobuf.Reflection"
+};
+static const ::_pbi::DescriptorTable* PROTOBUF_NONNULL const
+    descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_deps[1] = {
+        &::descriptor_table_google_2fprotobuf_2fdescriptor_2eproto,
+};
+static ::absl::once_flag descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_once;
+PROTOBUF_CONSTINIT const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto = {
+    false,
+    false,
+    304,
+    descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto,
+    "google/protobuf/compiler/csharp/c_sharp_features.proto",
+    &descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_once,
+    descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_deps,
+    1,
+    1,
+    schemas,
+    file_message_globals,
+    TableStruct_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto::offsets,
+    file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto,
+};
+namespace pb {
+// ===================================================================
+
+CSharpFeatures::CSharpFeatures(::google::protobuf::Arena* PROTOBUF_NULLABLE arena)
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+    : ::google::protobuf::Message(arena, CSharpFeatures_get_class_data()) {
+#else   // PROTOBUF_CUSTOM_VTABLE
+    : ::google::protobuf::Message(arena) {
+#endif  // PROTOBUF_CUSTOM_VTABLE
+  SharedCtor(arena);
+  // @@protoc_insertion_point(arena_constructor:pb.CSharpFeatures)
+}
+CSharpFeatures::CSharpFeatures(
+    ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const CSharpFeatures& from)
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+    : ::google::protobuf::Message(arena, CSharpFeatures_get_class_data()),
+#else   // PROTOBUF_CUSTOM_VTABLE
+    : ::google::protobuf::Message(arena),
+#endif  // PROTOBUF_CUSTOM_VTABLE
+      _impl_(from._impl_) {
+  _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(
+      from._internal_metadata_);
+}
+PROTOBUF_NDEBUG_INLINE CSharpFeatures::Impl_::Impl_(
+    [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility,
+    [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena)
+     {}
+
+inline void CSharpFeatures::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) {
+  new (&_impl_) Impl_(internal_visibility(), arena);
+  _impl_.nullable_reference_types_ = {};
+}
+CSharpFeatures::~CSharpFeatures() {
+  // @@protoc_insertion_point(destructor:pb.CSharpFeatures)
+  SharedDtor(*this);
+}
+inline void CSharpFeatures::SharedDtor(MessageLite& self) {
+  CSharpFeatures& this_ = static_cast<CSharpFeatures&>(self);
+  if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) {
+    this_.CheckHasBitConsistency();
+  }
+  this_._internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>();
+  ABSL_DCHECK(this_.GetArena() == nullptr);
+  this_._impl_.~Impl_();
+}
+
+#ifndef PROTOBUF_MESSAGE_GLOBALS
+PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const
+    ::google::protobuf::internal::ClassDataFull CSharpFeatures_class_data_ =
+        CSharpFeatures::InternalGenerateClassData_(CSharpFeatures_globals_._default);
+
+PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL
+CSharpFeatures::GetClassData() const {
+  ::google::protobuf::internal::PrefetchToLocalCache(&CSharpFeatures_class_data_);
+  ::google::protobuf::internal::PrefetchToLocalCache(CSharpFeatures_class_data_.tc_table);
+  return CSharpFeatures_class_data_.base();
+}
+#else
+PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL
+CSharpFeatures::GetClassData() const {
+  ::google::protobuf::internal::PrefetchToLocalCache(&CSharpFeatures_globals_);
+  ::google::protobuf::internal::PrefetchToLocalCache(
+      ::google::protobuf::internal::MessageGlobalsBase::ToParseTableBase(&CSharpFeatures_globals_));
+  return CSharpFeatures_globals_.GetClassData();
+}
+#endif  // !PROTOBUF_MESSAGE_GLOBALS
+#ifndef PROTOBUF_MESSAGE_GLOBALS
+PROTOBUF_CONSTINIT
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const CSharpFeatures::ParseTableT_
+    CSharpFeatures::_table_ =
+        CSharpFeatures::InternalGenerateParseTable_(CSharpFeatures_class_data_.base());
+#endif  // !PROTOBUF_MESSAGE_GLOBALS
+PROTOBUF_NOINLINE void CSharpFeatures::Clear() {
+// @@protoc_insertion_point(message_clear_start:pb.CSharpFeatures)
+  ::google::protobuf::internal::TSanWrite(&_impl_);
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.nullable_reference_types_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>();
+}
+
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+::uint8_t* PROTOBUF_NONNULL CSharpFeatures::_InternalSerialize(
+    const ::google::protobuf::MessageLite& base, ::uint8_t* PROTOBUF_NONNULL target,
+    ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) {
+  const CSharpFeatures& this_ = static_cast<const CSharpFeatures&>(base);
+#else   // PROTOBUF_CUSTOM_VTABLE
+::uint8_t* PROTOBUF_NONNULL CSharpFeatures::_InternalSerialize(
+    ::uint8_t* PROTOBUF_NONNULL target,
+    ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const {
+  const CSharpFeatures& this_ = *this;
+#endif  // PROTOBUF_CUSTOM_VTABLE
+  if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) {
+    this_.CheckHasBitConsistency();
+  }
+  // @@protoc_insertion_point(serialize_to_array_start:pb.CSharpFeatures)
+  ::uint32_t cached_has_bits = 0;
+  (void)cached_has_bits;
+
+  cached_has_bits = this_._impl_._has_bits_[0];
+  // optional bool nullable_reference_types = 1 [retention = RETENTION_RUNTIME, targets = TARGET_TYPE_FIELD, targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_FILE, edition_defaults = {
+  if (CheckHasBit(cached_has_bits, 0x00000001U)) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(
+        1, this_._internal_nullable_reference_types(), target);
+  }
+
+  if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) {
+    target =
+        ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+            this_._internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:pb.CSharpFeatures)
+  return target;
+}
+
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+::size_t CSharpFeatures::ByteSizeLong(const MessageLite& base) {
+  const CSharpFeatures& this_ = static_cast<const CSharpFeatures&>(base);
+#else   // PROTOBUF_CUSTOM_VTABLE
+::size_t CSharpFeatures::ByteSizeLong() const {
+  const CSharpFeatures& this_ = *this;
+#endif  // PROTOBUF_CUSTOM_VTABLE
+  // @@protoc_insertion_point(message_byte_size_start:pb.CSharpFeatures)
+  ::size_t total_size = 0;
+
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void)cached_has_bits;
+
+  cached_has_bits = this_._impl_._has_bits_[0];
+  total_size += static_cast<bool>(0x00000001U & cached_has_bits) * 2;
+  return this_.MaybeComputeUnknownFieldsSize(total_size,
+                                             &this_._impl_._cached_size_);
+}
+
+void CSharpFeatures::MergeImpl(::google::protobuf::MessageLite& to_msg,
+                      const ::google::protobuf::MessageLite& from_msg) {
+   auto* const _this = static_cast<CSharpFeatures*>(&to_msg);
+  auto& from = static_cast<const CSharpFeatures&>(from_msg);
+  if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) {
+    from.CheckHasBitConsistency();
+  }
+  // @@protoc_insertion_point(class_specific_merge_from_start:pb.CSharpFeatures)
+  ABSL_DCHECK_NE(&from, _this);
+  ::uint32_t cached_has_bits = 0;
+  (void)cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (CheckHasBit(cached_has_bits, 0x00000001U)) {
+    _this->_impl_.nullable_reference_types_ = from._impl_.nullable_reference_types_;
+  }
+  _this->_impl_._has_bits_[0] |= cached_has_bits;
+  _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>(
+      from._internal_metadata_);
+}
+
+void CSharpFeatures::CopyFrom(const CSharpFeatures& from) {
+  // @@protoc_insertion_point(class_specific_copy_from_start:pb.CSharpFeatures)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+
+void CSharpFeatures::InternalSwap(CSharpFeatures* PROTOBUF_RESTRICT PROTOBUF_NONNULL other) {
+  using ::std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  swap(_impl_.nullable_reference_types_, other->_impl_.nullable_reference_types_);
+}
+
+::google::protobuf::Metadata CSharpFeatures::GetMetadata() const {
+  return ::google::protobuf::Message::GetMetadataImpl(GetClassData()->full());
+}
+PROTOBUF_CONSTINIT PROTOC_EXPORT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::_pbi::ExtensionIdentifier<
+        ::google::protobuf::FeatureSet, ::_pbi::MessageTypeTraits< ::pb::CSharpFeatures >, 11, false>
+        csharp(kCsharpFieldNumber, &::pb::CSharpFeatures_globals_);
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace pb
+namespace google {
+namespace protobuf {
+}  // namespace protobuf
+}  // namespace google
+// @@protoc_insertion_point(global_scope)
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::std::false_type
+    _static_init2_ [[maybe_unused]] =
+        (::_pbi::AddDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto),
+        ::_pbi::ExtensionSet::RegisterMessageExtension(
+            &::google::protobuf::FeatureSet::default_instance(), 1004, 11,
+            false, false, &::pb::CSharpFeatures::default_instance(),
+            nullptr, ::_pbi::LazyAnnotation::kUndefined),
+         ::std::false_type{});
+#include "google/protobuf/port_undef.inc"
diff --git a/src/google/protobuf/compiler/csharp/c_sharp_features.pb.h b/src/google/protobuf/compiler/csharp/c_sharp_features.pb.h
new file mode 100755
index 0000000..4489e04
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/c_sharp_features.pb.h
@@ -0,0 +1,347 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// NO CHECKED-IN PROTOBUF GENCODE
+// source: google/protobuf/compiler/csharp/c_sharp_features.proto
+// Protobuf C++ Version: 7.36.0-dev
+
+#ifndef google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_2epb_2eh
+#define google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_2epb_2eh
+
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+// clang-format off
+#include "google/protobuf/runtime_version.h"
+#if PROTOBUF_VERSION != 7036000
+#error "Protobuf C++ gencode is built with an incompatible version of"
+#error "Protobuf C++ headers/runtime. See"
+#error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp"
+#endif
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/arena.h"
+#include "google/protobuf/arenastring.h"
+#include "google/protobuf/generated_message_tctable_decl.h"
+#include "google/protobuf/generated_message_util.h"
+#include "google/protobuf/metadata_lite.h"
+#include "google/protobuf/generated_message_reflection.h"
+#include "google/protobuf/message.h"
+#include "google/protobuf/message_lite.h"
+#include "google/protobuf/repeated_field.h"  // IWYU pragma: export
+#include "google/protobuf/extension_set.h"  // IWYU pragma: export
+#include "google/protobuf/unknown_field_set.h"
+#include "google/protobuf/descriptor.pb.h"
+// @@protoc_insertion_point(includes)
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto PROTOC_EXPORT
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template <typename T>
+::absl::string_view GetAnyMessageName();
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+// Internal implementation detail -- do not use these members.
+struct PROTOC_EXPORT TableStruct_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto {
+  static const ::uint32_t offsets[];
+};
+extern "C" {
+PROTOC_EXPORT extern const ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto;
+}  // extern "C"
+namespace pb {
+class CSharpFeatures;
+struct CSharpFeaturesGlobalsTypeInternal;
+#ifndef PROTOBUF_MESSAGE_GLOBALS
+PROTOC_EXPORT extern CSharpFeaturesGlobalsTypeInternal CSharpFeatures_globals_;
+PROTOC_EXPORT extern const ::google::protobuf::internal::ClassDataFull CSharpFeatures_class_data_;
+#else
+PROTOC_EXPORT extern const CSharpFeaturesGlobalsTypeInternal CSharpFeatures_globals_;
+#endif  // PROTOBUF_MESSAGE_GLOBALS
+}  // namespace pb
+namespace google {
+namespace protobuf {
+namespace internal {
+template <>
+inline ::absl::string_view GetFeatureSetDefaultsData<::pb::CSharpFeatures>() {
+  static constexpr char kDefaults[] = "CiEYhAciA+I+ACoXCAEQAhgCIAMoATACOAJAAUgB4j4CCAAKIRjnByID4j4AKhcIAhABGAEgAigBMAE4AkABSAHiPgIIAAohGOgHIg8IARABGAEgAigBMAHiPgAqCzgCQAFIAeI+AggACiEY6QciEwgBEAEYASACKAEwATgBQALiPgAqB0gB4j4CCAAKIRjqByIVCAEQARgBIAIoATABOANAAkgC4j4AKgXiPgIIAAohGI9OIhcIARABGAEgAigBMAE4A0ACSALiPgIIACoD4j4AIOYHKOoH";
+  return kDefaults;
+}
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace pb {
+
+// ===================================================================
+
+
+// -------------------------------------------------------------------
+
+class PROTOC_EXPORT  PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED CSharpFeatures final : public ::google::protobuf::Message
+/* @@protoc_insertion_point(class_definition:pb.CSharpFeatures) */ {
+ public:
+  inline CSharpFeatures() : CSharpFeatures(nullptr) {}
+  ~CSharpFeatures() PROTOBUF_FINAL;
+
+#if defined(PROTOBUF_CUSTOM_VTABLE)
+  void operator delete(CSharpFeatures* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) {
+    SharedDtor(*msg);
+    ::google::protobuf::internal::SizedDelete(msg, sizeof(CSharpFeatures));
+  }
+#endif
+
+  template <typename = void>
+  explicit constexpr CSharpFeatures(::google::protobuf::internal::ConstantInitialized,
+                           const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL
+                               class_data);
+
+  inline CSharpFeatures(const CSharpFeatures& from) : CSharpFeatures(nullptr, from) {}
+  inline CSharpFeatures(CSharpFeatures&& from) noexcept : CSharpFeatures(nullptr, ::std::move(from)) {}
+  inline CSharpFeatures& operator=(const CSharpFeatures& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline CSharpFeatures& operator=(CSharpFeatures&& from) noexcept {
+    if (this == &from) return *this;
+    if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  [[nodiscard]] inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance);
+  }
+  [[nodiscard]] inline ::google::protobuf::UnknownFieldSet* PROTOBUF_NONNULL
+  mutable_unknown_fields() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>();
+  }
+
+  [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL descriptor() {
+    return GetDescriptor();
+  }
+  [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL
+  GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  [[nodiscard]] static const ::google::protobuf::Reflection* PROTOBUF_NONNULL GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  [[nodiscard]] static const CSharpFeatures& default_instance() {
+    return *::google::protobuf::internal::MessageGlobalsBase::ToDefaultInstance<CSharpFeatures>(&CSharpFeatures_globals_);
+  }
+  static constexpr int kIndexInFileMessages = 0;
+  friend void swap(CSharpFeatures& a, CSharpFeatures& b) { a.Swap(&b); }
+  inline void Swap(CSharpFeatures* PROTOBUF_NONNULL other) {
+    if (other == this) return;
+    if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) {
+      InternalSwap(other);
+    } else {
+      ::google::protobuf::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(CSharpFeatures* PROTOBUF_NONNULL other) {
+    if (other == this) return;
+    ABSL_DCHECK(GetArena() == other->GetArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  [[nodiscard]] CSharpFeatures* PROTOBUF_NONNULL
+  New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const {
+    return ::google::protobuf::Message::DefaultConstruct<CSharpFeatures>(arena);
+  }
+  using ::google::protobuf::Message::CopyFrom;
+  void CopyFrom(const CSharpFeatures& from);
+  using ::google::protobuf::Message::MergeFrom;
+  void MergeFrom(const CSharpFeatures& from) { CSharpFeatures::MergeImpl(*this, from); }
+
+  private:
+  static void MergeImpl(::google::protobuf::MessageLite& to_msg,
+                        const ::google::protobuf::MessageLite& from_msg);
+
+  public:
+  [[nodiscard]] bool IsInitialized() const {
+    return true;
+  }
+  ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL;
+  #if defined(PROTOBUF_CUSTOM_VTABLE)
+  private:
+  [[nodiscard]] static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg);
+  [[nodiscard]] static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize(
+      const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target,
+      ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream);
+
+  public:
+  [[nodiscard]] ::size_t ByteSizeLong() const { return ByteSizeLong(*this); }
+  [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize(
+      ::uint8_t* PROTOBUF_NONNULL target,
+      ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const {
+    return _InternalSerialize(*this, target, stream);
+  }
+  #else   // PROTOBUF_CUSTOM_VTABLE
+  [[nodiscard]] ::size_t ByteSizeLong() const final;
+  [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize(
+      ::uint8_t* PROTOBUF_NONNULL target,
+      ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final;
+  #endif  // PROTOBUF_CUSTOM_VTABLE
+  [[nodiscard]] int GetCachedSize() const {
+    return _impl_._cached_size_.Get();
+  }
+
+  private:
+  void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena);
+  static void SharedDtor(MessageLite& self);
+  void InternalSwap(CSharpFeatures* PROTOBUF_NONNULL other);
+ private:
+  template <typename T>
+  friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)();
+  static ::absl::string_view FullMessageName() { return "pb.CSharpFeatures"; }
+
+  explicit CSharpFeatures(::google::protobuf::Arena* PROTOBUF_NULLABLE arena);
+  CSharpFeatures(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const CSharpFeatures& from);
+  CSharpFeatures(
+      ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, CSharpFeatures&& from) noexcept
+      : CSharpFeatures(arena) {
+    *this = ::std::move(from);
+  }
+  const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL;
+  static void* PROTOBUF_NONNULL PlacementNew_(
+      const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem,
+      ::google::protobuf::Arena* PROTOBUF_NULLABLE arena);
+  static constexpr auto InternalNewImpl_();
+
+ public:
+  static constexpr auto InternalGenerateClassData_(
+      const MessageLite& prototype,
+      const ::google::protobuf::internal::TcParseTableBase* PROTOBUF_NULLABLE tc_table = nullptr);
+
+  [[nodiscard]] ::google::protobuf::Metadata GetMetadata() const;
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+  enum : int {
+    kNullableReferenceTypesFieldNumber = 1,
+  };
+  // optional bool nullable_reference_types = 1 [retention = RETENTION_RUNTIME, targets = TARGET_TYPE_FIELD, targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_FILE, edition_defaults = {
+  [[nodiscard]] bool has_nullable_reference_types() const;
+  void clear_nullable_reference_types() ;
+  [[nodiscard]] bool nullable_reference_types() const;
+  void set_nullable_reference_types(bool value);
+
+  private:
+  bool _internal_nullable_reference_types() const;
+  void _internal_set_nullable_reference_types(bool value);
+
+  public:
+  // @@protoc_insertion_point(class_scope:pb.CSharpFeatures)
+ private:
+  class _Internal;
+  using ParseTableT_ =
+      ::google::protobuf::internal::TcParseTable<0, 1,
+                          0, 0,
+                          2>;
+  static constexpr ParseTableT_ InternalGenerateParseTable_(
+      const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL class_data);
+  friend class ::google::protobuf::internal::TcParser;
+  #ifndef PROTOBUF_MESSAGE_GLOBALS
+  static const ParseTableT_ _table_;
+  #endif
+
+  friend class ::google::protobuf::MessageLite;
+  friend class ::google::protobuf::Arena;
+  friend ::google::protobuf::internal::PrivateAccess;
+  template <typename T>
+  friend class ::google::protobuf::Arena::InternalHelper;
+  using InternalArenaConstructable_ = void;
+  using DestructorSkippable_ = void;
+  struct Impl_ {
+    inline explicit constexpr Impl_(::google::protobuf::internal::InternalVisibility visibility,
+                                    ::google::protobuf::internal::ConstantInitialized) noexcept;
+    inline explicit Impl_(
+        ::google::protobuf::internal::InternalVisibility visibility,
+        ::google::protobuf::Arena* PROTOBUF_NULLABLE arena);
+    inline explicit Impl_(
+        ::google::protobuf::internal::InternalVisibility visibility,
+        ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from,
+        const CSharpFeatures& from_msg);
+    ::google::protobuf::internal::HasBits<1> _has_bits_;
+    ::google::protobuf::internal::CachedSize _cached_size_;
+    bool nullable_reference_types_;
+    PROTOBUF_TSAN_DECLARE_MEMBER
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto;
+};
+
+// ===================================================================
+
+
+
+inline constexpr int kCsharpFieldNumber = 1004;
+PROTOC_EXPORT extern ::google::protobuf::internal::ExtensionIdentifier<
+    ::google::protobuf::FeatureSet, ::google::protobuf::internal::MessageTypeTraits< ::pb::CSharpFeatures >, 11, false>(csharp);
+
+// ===================================================================
+
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// CSharpFeatures
+
+// optional bool nullable_reference_types = 1 [retention = RETENTION_RUNTIME, targets = TARGET_TYPE_FIELD, targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_FILE, edition_defaults = {
+inline bool CSharpFeatures::has_nullable_reference_types() const {
+  bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000001U);
+  return value;
+}
+inline void CSharpFeatures::clear_nullable_reference_types() {
+  ::google::protobuf::internal::TSanWrite(&_impl_);
+  _impl_.nullable_reference_types_ = false;
+  ClearHasBit(_impl_._has_bits_[0], 0x00000001U);
+}
+inline bool CSharpFeatures::nullable_reference_types() const {
+  // @@protoc_insertion_point(field_get:pb.CSharpFeatures.nullable_reference_types)
+  return _internal_nullable_reference_types();
+}
+inline void CSharpFeatures::set_nullable_reference_types(bool value) {
+  _internal_set_nullable_reference_types(value);
+  SetHasBit(_impl_._has_bits_[0], 0x00000001U);
+  // @@protoc_insertion_point(field_set:pb.CSharpFeatures.nullable_reference_types)
+}
+inline bool CSharpFeatures::_internal_nullable_reference_types() const {
+  ::google::protobuf::internal::TSanRead(&_impl_);
+  return _impl_.nullable_reference_types_;
+}
+inline void CSharpFeatures::_internal_set_nullable_reference_types(bool value) {
+  ::google::protobuf::internal::TSanWrite(&_impl_);
+  _impl_.nullable_reference_types_ = value;
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace pb
+
+
+// @@protoc_insertion_point(global_scope)
+
+#include "google/protobuf/port_undef.inc"
+// clang-format on
+
+#endif  // google_2fprotobuf_2fcompiler_2fcsharp_2fc_5fsharp_5ffeatures_2eproto_2epb_2eh
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
index 290b38c..dd3b7a7 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -14,6 +14,7 @@
 
 #include "absl/log/absl_log.h"
 #include "google/protobuf/compiler/code_generator.h"
+#include "google/protobuf/compiler/csharp/csharp_generator.h"
 #include "google/protobuf/compiler/csharp/csharp_helpers.h"
 #include "google/protobuf/compiler/csharp/names.h"
 #include "google/protobuf/descriptor.h"
@@ -115,6 +116,9 @@
                        absl::StrCat("other.", (*variables)["property_name"],
                                     " != ", (*variables)["default_value"])});
   }
+  // This isn't valid everywhere, but we assume that the code which uses
+  // the variable will only do so in a context where the annotation is valid.
+  (*variables)["nrt_annotation"] = nrt_enabled_ ? "?" : "";
 }
 
 void FieldGeneratorBase::SetCommonOneofFieldVariables(
@@ -129,6 +133,9 @@
   }
   (*variables)["oneof_case_name"] = oneof_case_name();
   (*variables)["oneof_property_name"] = oneof_property_name();
+  // This isn't valid everywhere, but we assume that the code which uses
+  // the variable will only do so in a context where the annotation is valid.
+  (*variables)["nrt_annotation"] = nrt_enabled_ ? "?" : "";
 }
 
 FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
@@ -136,6 +143,9 @@
     : SourceGeneratorBase(options),
       descriptor_(descriptor),
       presenceIndex_(presenceIndex) {
+  nrt_enabled_ = Generator::GetResolvedSourceFeatures(*descriptor->file())
+                     .GetExtension(pb::csharp)
+                     .nullable_reference_types();
   SetCommonFieldVariables(&variables_);
 }
 
@@ -216,10 +226,12 @@
         const FieldDescriptor* wrapped_field =
             descriptor->message_type()->field(0);
         std::string wrapped_field_type_name = type_name(wrapped_field);
-        // String and ByteString go to the same type; other wrapped types
-        // go to the nullable equivalent.
-        if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
-            wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
+        // String and ByteString go to the same type (unless nullable reference
+        // type is supported for this field); other wrapped types go to the
+        // nullable equivalent.
+        if (!nrt_enabled_ &&
+            (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
+             wrapped_field->type() == FieldDescriptor::TYPE_BYTES)) {
           return wrapped_field_type_name;
         } else {
           return absl::StrCat(wrapped_field_type_name, "?");
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h
index 39db3aa..c3347d7 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.h
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h
@@ -55,6 +55,8 @@
  protected:
   const FieldDescriptor* descriptor_;
   const int presenceIndex_;
+  // NRT = Nullable Reference Types
+  bool nrt_enabled_;
   absl::flat_hash_map<absl::string_view, std::string> variables_;
 
   void AddDeprecatedFlag(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h
index 8fa15e5..84c7c1e 100644
--- a/src/google/protobuf/compiler/csharp/csharp_generator.h
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.h
@@ -11,8 +11,10 @@
 #define GOOGLE_PROTOBUF_COMPILER_CSHARP_CSHARP_GENERATOR_H__
 
 #include <string>
+#include <vector>
 
 #include "google/protobuf/compiler/code_generator.h"
+#include "google/protobuf/compiler/csharp/c_sharp_features.pb.h"
 #include "google/protobuf/port_def.inc"
 
 namespace google {
@@ -37,6 +39,11 @@
   Edition GetMinimumEdition() const override { return Edition::EDITION_PROTO2; }
   Edition GetMaximumEdition() const override { return Edition::EDITION_2024; }
   using CodeGenerator::GetEdition;
+
+  std::vector<const FieldDescriptor*> GetFeatureExtensions() const override {
+    return {GetExtensionReflection(pb::csharp)};
+  }
+  using CodeGenerator::GetResolvedSourceFeatures;
 };
 
 }  // namespace csharp
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
index d80b514..8c2b0b4 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -8,16 +8,15 @@
 #include "google/protobuf/compiler/csharp/csharp_message.h"
 
 #include <algorithm>
-#include <sstream>
 #include <string>
 
 #include "absl/container/flat_hash_map.h"
 #include "absl/log/absl_log.h"
 #include "absl/strings/str_cat.h"
-#include "google/protobuf/compiler/code_generator.h"
 #include "google/protobuf/compiler/csharp/csharp_doc_comment.h"
 #include "google/protobuf/compiler/csharp/csharp_enum.h"
 #include "google/protobuf/compiler/csharp/csharp_field_base.h"
+#include "google/protobuf/compiler/csharp/csharp_generator.h"
 #include "google/protobuf/compiler/csharp/csharp_helpers.h"
 #include "google/protobuf/compiler/csharp/csharp_options.h"
 #include "google/protobuf/compiler/csharp/names.h"
@@ -60,6 +59,9 @@
     }
   }
   has_bit_field_count_ = (presence_bit_count + 31) / 32;
+  nrt_enabled_ = Generator::GetResolvedSourceFeatures(*descriptor->file())
+                     .GetExtension(pb::csharp)
+                     .nullable_reference_types();
 }
 
 MessageGenerator::~MessageGenerator() = default;
@@ -93,6 +95,7 @@
   absl::flat_hash_map<absl::string_view, std::string> vars;
   vars["class_name"] = class_name();
   vars["access_level"] = class_access_level();
+  vars["nrt_annotation"] = nrt_enabled_ ? "?" : "";
 
   WriteMessageDocComment(printer, options(), descriptor_);
   AddDeprecatedFlag(printer);
@@ -120,23 +123,26 @@
       "private static readonly pb::MessageParser<$class_name$> _parser = new "
       "pb::MessageParser<$class_name$>(() => new $class_name$());\n");
 
-  printer->Print("private pb::UnknownFieldSet _unknownFields;\n");
+  printer->Print(
+      vars, "private pb::UnknownFieldSet$nrt_annotation$ _unknownFields;\n");
 
   if (has_extension_ranges_) {
     if (IsDescriptorProto(descriptor_->file())) {
       printer->Print(vars,
                      // CustomOptions compatibility
-                     "internal pb::ExtensionSet<$class_name$> _extensions;\n");
+                     "internal pb::ExtensionSet<$class_name$>$nrt_annotation$ "
+                     "_extensions;\n");
     } else {
       printer->Print(vars,
-                     "private pb::ExtensionSet<$class_name$> _extensions;\n");
+                     "private pb::ExtensionSet<$class_name$>$nrt_annotation$ "
+                     "_extensions;\n");
     }
 
     // a read-only property for fast
     // retrieval of the set in IsInitialized
     printer->Print(vars,
-                   "private pb::ExtensionSet<$class_name$> _Extensions { get { "
-                   "return _extensions; } }\n");
+                   "private pb::ExtensionSet<$class_name$>$nrt_annotation$ "
+                   " _Extensions { get { return _extensions; } }\n");
   }
 
   for (int i = 0; i < has_bit_field_count_; i++) {
@@ -256,7 +262,7 @@
         "TValue> extension) {\n"
         "  return pb::ExtensionSet.Get(ref _extensions, extension);\n"
         "}\n"
-        "public pbc::RepeatedField<TValue> "
+        "public pbc::RepeatedField<TValue>$nrt_annotation$ "
         "GetExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> "
         "extension) {\n"
         "  return pb::ExtensionSet.Get(ref _extensions, extension);\n"
@@ -417,16 +423,17 @@
 void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
   absl::flat_hash_map<absl::string_view, std::string> vars;
   vars["class_name"] = class_name();
+  vars["nrt_annotation"] = nrt_enabled_ ? "?" : "";
 
   // Equality
   WriteGeneratedCodeAttributes(printer);
   printer->Print(vars,
-                 "public override bool Equals(object other) {\n"
+                 "public override bool Equals(object$nrt_annotation$ other) {\n"
                  "  return Equals(other as $class_name$);\n"
                  "}\n\n");
   WriteGeneratedCodeAttributes(printer);
   printer->Print(vars,
-                 "public bool Equals($class_name$ other) {\n"
+                 "public bool Equals($class_name$$nrt_annotation$ other) {\n"
                  "  if (ReferenceEquals(other, null)) {\n"
                  "    return false;\n"
                  "  }\n"
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h
index 96e47b3..abaac58 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.h
+++ b/src/google/protobuf/compiler/csharp/csharp_message.h
@@ -40,6 +40,8 @@
   std::vector<const FieldDescriptor*> fields_by_number_;
   int has_bit_field_count_;
   bool has_extension_ranges_;
+  // NRT = Nullable Reference Types
+  bool nrt_enabled_;
 
   void GenerateMessageSerializationMethods(io::Printer* printer);
   void GenerateWriteToBody(io::Printer* printer, bool use_write_context);
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
index 0e6eee7..2c3f093 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -35,19 +35,17 @@
 MessageFieldGenerator::~MessageFieldGenerator() = default;
 
 void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
-  printer->Print(
-    variables_,
-    "private $type_name$ $name$_;\n");
+  printer->Print(variables_, "private $type_name$$nrt_annotation$ $name$_;\n");
   WritePropertyDocComment(printer, options(), descriptor_);
   AddPublicMemberAttributes(printer);
   printer->Print(
-    variables_,
-    "$access_level$ $type_name$ $property_name$ {\n"
-    "  get { return $name$_; }\n"
-    "  set {\n"
-    "    $name$_ = value;\n"
-    "  }\n"
-    "}\n");
+      variables_,
+      "$access_level$ $type_name$$nrt_annotation$ $property_name$ {\n"
+      "  get { return $name$_; }\n"
+      "  set {\n"
+      "    $name$_ = value;\n"
+      "  }\n"
+      "}\n");
   if (SupportsPresenceApi(descriptor_)) {
     printer->Print(
       variables_,
@@ -189,14 +187,17 @@
   WritePropertyDocComment(printer, options(), descriptor_);
   AddPublicMemberAttributes(printer);
   printer->Print(
-    variables_,
-    "$access_level$ $type_name$ $property_name$ {\n"
-    "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
-    "  set {\n"
-    "    $oneof_name$_ = value;\n"
-    "    $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$oneof_case_name$;\n"
-    "  }\n"
-    "}\n");
+      variables_,
+      "$access_level$ $type_name$$nrt_annotation$ $property_name$ {\n"
+      "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : "
+      "null; }\n"
+      "  set {\n"
+      "    $oneof_name$_ = value;\n"
+      "    $oneof_name$Case_ = value == null ? "
+      "$oneof_property_name$OneofCase.None : "
+      "$oneof_property_name$OneofCase.$oneof_case_name$;\n"
+      "  }\n"
+      "}\n");
   if (SupportsPresenceApi(descriptor_)) {
     printer->Print(
       variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
index 1ed4c9f..58309d3 100644
--- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -66,11 +66,15 @@
     std::string default_value = variables_["default_value"];
     variables_["default_value_access"] = std::move(default_value);
   }
+  // For string and bytes proto fields, the C# field is nullable, but the
+  // property isn't. (The null value is used for presence.)
+  variables_["nrt_field_annotation"] =
+      nrt_enabled_ && IsNullable(descriptor_) ? "?" : "";
 
   // Declare the field itself.
   printer->Print(
-    variables_,
-    "private $type_name$ $name_def_message$;\n");
+      variables_,
+      "private $type_name$$nrt_field_annotation$ $name_def_message$;\n");
 
   WritePropertyDocComment(printer, options(), descriptor_);
   AddPublicMemberAttributes(printer);
diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
index 2194dc5..e1af11d 100644
--- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -13,10 +13,12 @@
 #include "google/protobuf/compiler/code_generator.h"
 #include "google/protobuf/compiler/csharp/csharp_enum.h"
 #include "google/protobuf/compiler/csharp/csharp_field_base.h"
+#include "google/protobuf/compiler/csharp/csharp_generator.h"
 #include "google/protobuf/compiler/csharp/csharp_helpers.h"
 #include "google/protobuf/compiler/csharp/csharp_message.h"
 #include "google/protobuf/compiler/csharp/csharp_options.h"
 #include "google/protobuf/compiler/csharp/names.h"
+#include "google/protobuf/compiler/csharp/c_sharp_features.pb.h"
 #include "google/protobuf/descriptor.h"
 #include "google/protobuf/descriptor.pb.h"
 #include "google/protobuf/io/printer.h"
@@ -36,6 +38,9 @@
   namespace_ = GetFileNamespace(file);
   reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
   extensionClassname_ = GetExtensionClassUnqualifiedName(file);
+  nrt_enabled_ = Generator::GetResolvedSourceFeatures(*file)
+                     .GetExtension(pb::csharp)
+                     .nullable_reference_types();
 }
 
 ReflectionClassGenerator::~ReflectionClassGenerator() = default;
@@ -120,6 +125,10 @@
     printer->Print("\n");
   }
 
+  if (nrt_enabled_) {
+    printer->Print("#nullable enable annotations\n");
+  }
+
   printer->Print(
     "/// <summary>Holder for reflection information generated from $file_name$</summary>\n"
     "$access_level$ static partial class $reflection_class_name$ {\n"
diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
index af29bf8..306b665 100644
--- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@@ -36,6 +36,8 @@
   std::string namespace_;
   std::string reflectionClassname_;
   std::string extensionClassname_;
+  // Whether or not nullable reference types are enabled for the whole file.
+  bool nrt_enabled_;
 
   void WriteIntroduction(io::Printer* printer);
   void WriteDescriptor(io::Printer* printer);