internal change

PiperOrigin-RevId: 922907524
diff --git a/python/BUILD.bazel b/python/BUILD.bazel
index d698bf9..f282a60 100644
--- a/python/BUILD.bazel
+++ b/python/BUILD.bazel
@@ -112,6 +112,7 @@
     features = UPB_DEFAULT_FEATURES,
     target_compatible_with = select(_message_target_compatible_with),
     deps = [
+        ":breaking_changes",
         "//src/google/protobuf:descriptor_upb_reflection_proto",
         "//third_party/utf8_range",
         "//upb/base",
diff --git a/python/build_targets.bzl b/python/build_targets.bzl
index d4c86aa..93ec72a 100644
--- a/python/build_targets.bzl
+++ b/python/build_targets.bzl
@@ -108,6 +108,12 @@
             "define": "allow_oversize_protos=true",
         },
     )
+    cc_library(
+        name = "breaking_changes",
+        hdrs = ["google/protobuf/breaking_changes.h"],
+        visibility = ["//python:__subpackages__"],
+    )
+
     cc_binary(
         name = "google/protobuf/pyext/_message.so",
         srcs = native.glob([
@@ -136,6 +142,7 @@
         ],
         deps = [
             ":proto_api",
+            ":breaking_changes",
             "//src/google/protobuf",
             "//src/google/protobuf:port",
             "//src/google/protobuf:protobuf_lite",
@@ -536,6 +543,7 @@
             ":python_src_files",
             "README.md",
             "google/__init__.py",
+            "google/protobuf/breaking_changes.h",
         ],
         strip_prefix = "",
         visibility = ["//python/dist:__pkg__"],
@@ -554,6 +562,7 @@
             "MANIFEST.in",
             "README.md",
             "build_targets.bzl",
+            "google/protobuf/breaking_changes.h",
             "google/protobuf/proto_api.h",
             "google/protobuf/pyext/README",
             "google/protobuf/python_protobuf.h",
diff --git a/python/descriptor.c b/python/descriptor.c
index a176bca..895a0ab 100644
--- a/python/descriptor.c
+++ b/python/descriptor.c
@@ -7,6 +7,7 @@
 
 #include "python/descriptor.h"
 
+#include "google/protobuf/breaking_changes.h"
 #include "python/convert.h"
 #include "python/descriptor_containers.h"
 #include "python/descriptor_pool.h"
@@ -138,7 +139,7 @@
       upb_Message_ClearFieldByDef(opts2, field);
     }
 
-#if UPB_FUTURE_FREEZE_OPTIONS
+#if PROTOBUF_PY_FUTURE_FREEZE_OPTIONS
     upb_Message_Freeze(opts2, opts2_layout);
 #endif
     *cached = PyUpb_Message_Get(opts2, m, py_arena);
diff --git a/python/descriptor_containers.c b/python/descriptor_containers.c
index 869d900..1bfbc69 100644
--- a/python/descriptor_containers.c
+++ b/python/descriptor_containers.c
@@ -7,11 +7,14 @@
 
 #include "python/descriptor_containers.h"
 
+#include "google/protobuf/breaking_changes.h"
 #include "python/descriptor.h"
 #include "python/protobuf.h"
-#include "upb/port/def.inc"
 #include "upb/reflection/def.h"
 
+// Must be last.
+#include "upb/port/def.inc"
+
 // Implements __repr__ as str(dict(self)).
 static PyObject* PyUpb_DescriptorMap_Repr(PyObject* _self) {
   PyObject* dict = PyDict_New();
@@ -231,7 +234,7 @@
   }
 
   if (!PyList_Check(other)) {
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
     return kPyUpb_CompareNotImplemented;
 #else
     return kPyUpb_CompareNotEqual;
@@ -273,7 +276,7 @@
   PyUpb_CompareResult eq = PyUpb_GenericSequence_IsEqual(self, other);
   switch (eq) {
     case kPyUpb_CompareNotImplemented:
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
       Py_RETURN_NOTIMPLEMENTED;
 #else
       UPB_UNREACHABLE();  // Unreachable when this breaking change is disabled.
@@ -551,7 +554,7 @@
   }
 
   if (!PyDict_Check(other)) {
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
     return kPyUpb_CompareNotImplemented;
 #else
     return kPyUpb_CompareNotEqual;
@@ -579,7 +582,7 @@
   PyUpb_CompareResult eq = PyUpb_ByNameMap_IsEqual(self, other);
   switch (eq) {
     case kPyUpb_CompareNotImplemented:
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
       Py_RETURN_NOTIMPLEMENTED;
 #else
       UPB_UNREACHABLE();  // Unreachable when this breaking change is disabled.
@@ -804,7 +807,7 @@
   }
 
   if (!PyDict_Check(other)) {
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
     return kPyUpb_CompareNotImplemented;
 #else
     return kPyUpb_CompareNotEqual;
@@ -832,7 +835,7 @@
   PyUpb_CompareResult eq = PyUpb_ByNumberMap_IsEqual(self, other);
   switch (eq) {
     case kPyUpb_CompareNotImplemented:
-#if UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
       Py_RETURN_NOTIMPLEMENTED;
 #else
       UPB_UNREACHABLE();  // Unreachable when this breaking change is disabled.
diff --git a/python/google/protobuf/breaking_changes.h b/python/google/protobuf/breaking_changes.h
new file mode 100644
index 0000000..87a651d
--- /dev/null
+++ b/python/google/protobuf/breaking_changes.h
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2024 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 THIRD_PARTY_PY_GOOGLE_PROTOBUF_BREAKING_CHANGES_H_
+#define THIRD_PARTY_PY_GOOGLE_PROTOBUF_BREAKING_CHANGES_H_
+
+// Future versions of Protobuf Python will include breaking changes.
+// This file tracks Python-specific breaking changes that need to wait,
+// unlike upb-core breaking changes which can land immediately.
+
+#ifdef PROTOBUF_PY_FUTURE_BREAKING_CHANGES
+
+// Removes non-standard clamping behavior in RepeatedContainer.pop()
+// Owner: runze@
+#define PROTOBUF_PY_FUTURE_REMOVE_POP_CLAMP 1
+
+// Fix PyProto C++ and upb implementations to return NotImplemented in
+// descriptor container equality checks for unrecognized types.
+// Owner: runze@
+#define PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 1
+
+// Make GetOptions() return immutable options.
+// Owner: runze@
+#define PROTOBUF_PY_FUTURE_FREEZE_OPTIONS 1
+
+#else
+
+#define PROTOBUF_PY_FUTURE_REMOVE_POP_CLAMP 0
+
+#define PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 0
+
+#define PROTOBUF_PY_FUTURE_FREEZE_OPTIONS 0
+
+#endif
+
+#endif  // THIRD_PARTY_PY_GOOGLE_PROTOBUF_BREAKING_CHANGES_H_
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 3d2745c..8e7b7d6 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -39,6 +39,7 @@
 #include "absl/strings/string_view.h"
 #include "google/protobuf/descriptor.h"
 #include "google/protobuf/port_def.inc"
+#include "google/protobuf/breaking_changes.h"
 #include "google/protobuf/pyext/descriptor.h"
 #include "google/protobuf/pyext/descriptor_pool.h"
 #include "google/protobuf/pyext/scoped_pyobject_ptr.h"
@@ -346,7 +347,7 @@
     return CompareResult::kEqual;
   }
 
-#if PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
   // Any other object is not implemented.
   return CompareResult::kNotImplemented;
 #else
@@ -400,7 +401,7 @@
     return CompareResult::kEqual;
   }
 
-#if PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
   // Any other object is not implemented.
   return CompareResult::kNotImplemented;
 #else
@@ -424,7 +425,7 @@
   }
   switch (result) {
     case CompareResult::kNotImplemented:
-#if PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
+#if PROTOBUF_PY_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
       Py_RETURN_NOTIMPLEMENTED;
 #else
       return nullptr;  // Unreachable when this breaking change is disabled.
diff --git a/python/repeated.c b/python/repeated.c
index 4e2caf5..2177053 100644
--- a/python/repeated.c
+++ b/python/repeated.c
@@ -7,9 +7,12 @@
 
 #include "python/repeated.h"
 
+#include "google/protobuf/breaking_changes.h"
 #include "python/convert.h"
 #include "python/message.h"
 #include "python/protobuf.h"
+
+// Must be last.
 #include "upb/port/def.inc"
 
 static PyObject* PyUpb_RepeatedCompositeContainer_Append(PyObject* _self,
@@ -452,10 +455,10 @@
   if (!arr) return NULL;
   size_t size = upb_Array_Size(arr);
   if (index < 0) index += size;
-#if UPB_FUTURE_REMOVE_POP_CLAMP
+#if PROTOBUF_PY_FUTURE_REMOVE_POP_CLAMP
 #else
   if (index >= size) index = size - 1;
-#endif  // UPB_FUTURE_REMOVE_POP_CLAMP
+#endif  // PROTOBUF_PY_FUTURE_REMOVE_POP_CLAMP
   PyObject* ret = PyUpb_RepeatedContainer_Item(_self, index);
   if (!ret) return NULL;
   upb_Array_Delete(self->ptr.arr, index, 1);
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 77c833f..22cadd8 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -132,16 +132,10 @@
 // Owner: ckennelly@, mkruskal@
 #define PROTOBUF_FUTURE_ADD_NODISCARD [[nodiscard]]
 
-// Fix PyProto C++ and upb implementations to return NotImplemented in descriptor container equality checks for unrecognized types.
-// Owner: runze@
-#define PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 1
-
 #else
 
 #define PROTOBUF_FUTURE_ADD_NODISCARD
 
-#define PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 0
-
 #endif
 
 #define PROTOBUF_FUTURE_ADD_EARLY_NODISCARD [[nodiscard]]
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index d411478..0c1708a 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -82,7 +82,6 @@
 #undef PROTOBUF_FUTURE_ADD_NODISCARD
 #undef PROTOBUF_FUTURE_ADD_EARLY_NODISCARD
 #undef PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED
-#undef PROTOBUF_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
 #endif
 
 #include "google/protobuf/os_macros_restore.inc"
diff --git a/upb/port/def.inc b/upb/port/def.inc
index a638526..8010861 100644
--- a/upb/port/def.inc
+++ b/upb/port/def.inc
@@ -750,32 +750,5 @@
 #define UPB_WEAK_ALIAS(type, from, to) weak_alias_not_supported_on_this_platform
 #define UPB_STRONG_ALIAS(type, from, to) \
   strong_alias_not_supported_on_this_platform
-#endif
-
-// Future versions of upb will include breaking changes to some APIs.
-// This macro can be set to enable these API changes ahead of time, so that
-// user code can be updated before upgrading versions of protobuf.
-#ifdef UPB_FUTURE_BREAKING_CHANGES
-
-// Removes non-standard clamping behavior in RepeatedContainer.pop()
-// Owner: runze@
-#define UPB_FUTURE_REMOVE_POP_CLAMP 1
-
-// Fix PyProto C++ and upb implementations to return NotImplemented in
-// descriptor container equality checks for unrecognized types.
-// Owner: runze@
-#define UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 1
-
-// Make GetOptions() return immutable options.
-// Owner: runze@
-#define UPB_FUTURE_FREEZE_OPTIONS 1
-
-#else
-
-#define UPB_FUTURE_REMOVE_POP_CLAMP 0
-
-#define UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED 0
-
-#define UPB_FUTURE_FREEZE_OPTIONS 0
 
 #endif
diff --git a/upb/port/undef.inc b/upb/port/undef.inc
index 4f95de9..d02f4d0 100644
--- a/upb/port/undef.inc
+++ b/upb/port/undef.inc
@@ -74,10 +74,6 @@
 #undef UPB_LINKARR_APPEND
 #undef UPB_LINKARR_START
 #undef UPB_LINKARR_STOP
-#undef UPB_FUTURE_BREAKING_CHANGES
-#undef UPB_FUTURE_REMOVE_POP_CLAMP
-#undef UPB_FUTURE_CONTAINER_EQ_RETURNS_NOTIMPLEMENTED
-#undef UPB_FUTURE_FREEZE_OPTIONS
 #undef UPB_HAS_ATTRIBUTE
 #undef UPB_HAS_CPP_ATTRIBUTE
 #undef UPB_HAS_BUILTIN