Sync from Piper @432209397

PROTOBUF_SYNC_PIPER
diff --git a/CHANGES.txt b/CHANGES.txt
index d443caf..0385e5c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -24,7 +24,8 @@
   * Fix comments for message set wire format.
 
   Kotlin
-  * Add orNull extensions for optional message fields in Kotlin.
+  * Add orNull extensions for optional message fields.
+  * Add orNull extensions to all proto3 message fields.
 
   Python
   * Fix type annotations of some Duration and Timestamp methods.
@@ -90,6 +91,7 @@
   * Add missing overload for reference wrapped fields.
   * Add MergedDescriptorDatabase::FindAllFileNames()
   * RepeatedField now defines an iterator type instead of using a pointer.
+  * Remove obsolete macros GOOGLE_PROTOBUF_HAS_ONEOF and GOOGLE_PROTOBUF_HAS_ARENAS.
 
 
 2022-01-28 version 3.19.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 2366d4b..7315733 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Minimum CMake required
-cmake_minimum_required(VERSION 3.1.3)
+cmake_minimum_required(VERSION 3.10)
 
 if(protobuf_VERBOSE)
   message(STATUS "Protocol Buffers Configuring...")
@@ -127,6 +127,30 @@
   add_definitions(-DGOOGLE_PROTOBUF_NO_RTTI=1)
 endif()
 
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map
+"{
+  global:
+    main;
+  local:
+    *;
+};")
+# CheckLinkerFlag module available in CMake >=3.18.
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18)
+  include(CheckLinkerFlag)
+  check_linker_flag(CXX -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map protobuf_HAVE_LD_VERSION_SCRIPT)
+else()
+  include(CheckCXXSourceCompiles)
+  set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+  set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map)
+  check_cxx_source_compiles("
+    int main() {
+      return 0;
+    }
+  " protobuf_HAVE_LD_VERSION_SCRIPT)
+  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
+endif()
+file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map)
+
 find_package(Threads REQUIRED)
 
 set(_protobuf_FIND_ZLIB)
@@ -182,7 +206,7 @@
   # Prior to CMake 3.15, the MSVC runtime library was pushed into the same flags
   # making programmatic control difficult.  Prefer the functionality in newer
   # CMake versions when available.
-  if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15)
+  if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
     if (protobuf_MSVC_STATIC_RUNTIME)
         set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$<CONFIG:Debug>:Debug>)
     else()
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
index 5e98748..6cc547e 100644
--- a/cmake/libprotobuf-lite.cmake
+++ b/cmake/libprotobuf-lite.cmake
@@ -93,6 +93,11 @@
 
 add_library(libprotobuf-lite ${protobuf_SHARED_OR_STATIC}
   ${libprotobuf_lite_files} ${libprotobuf_lite_includes} ${libprotobuf_lite_rc_files})
+if(protobuf_HAVE_LD_VERSION_SCRIPT)
+  target_link_options(libprotobuf-lite PRIVATE -Wl,--version-script=${protobuf_source_dir}/src/libprotobuf-lite.map)
+  set_target_properties(libprotobuf-lite PROPERTIES
+    LINK_DEPENDS ${protobuf_source_dir}/src/libprotobuf-lite.map)
+endif()
 target_link_libraries(libprotobuf-lite ${CMAKE_THREAD_LIBS_INIT})
 if(protobuf_LINK_LIBATOMIC)
   target_link_libraries(libprotobuf-lite atomic)
@@ -108,6 +113,7 @@
 endif()
 set_target_properties(libprotobuf-lite PROPERTIES
     VERSION ${protobuf_VERSION}
+    SOVERSION 30
     OUTPUT_NAME ${LIB_PREFIX}protobuf-lite
     DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
 add_library(protobuf::libprotobuf-lite ALIAS libprotobuf-lite)
diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake
index db2b30c..9e08ebf 100644
--- a/cmake/libprotobuf.cmake
+++ b/cmake/libprotobuf.cmake
@@ -90,7 +90,6 @@
   ${protobuf_source_dir}/src/google/protobuf/util/delimited_message_util.h
   ${protobuf_source_dir}/src/google/protobuf/util/field_comparator.h
   ${protobuf_source_dir}/src/google/protobuf/util/field_mask_util.h
-  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_escaping.h
   ${protobuf_source_dir}/src/google/protobuf/util/json_util.h
   ${protobuf_source_dir}/src/google/protobuf/util/message_differencer.h
   ${protobuf_source_dir}/src/google/protobuf/util/time_util.h
@@ -108,6 +107,11 @@
 
 add_library(libprotobuf ${protobuf_SHARED_OR_STATIC}
   ${libprotobuf_lite_files} ${libprotobuf_files} ${libprotobuf_includes} ${libprotobuf_rc_files})
+if(protobuf_HAVE_LD_VERSION_SCRIPT)
+  target_link_options(libprotobuf PRIVATE -Wl,--version-script=${protobuf_source_dir}/src/libprotobuf.map)
+  set_target_properties(libprotobuf PROPERTIES
+    LINK_DEPENDS ${protobuf_source_dir}/src/libprotobuf.map)
+endif()
 target_link_libraries(libprotobuf ${CMAKE_THREAD_LIBS_INIT})
 if(protobuf_WITH_ZLIB)
   target_link_libraries(libprotobuf ${ZLIB_LIBRARIES})
@@ -126,7 +130,6 @@
 endif()
 set_target_properties(libprotobuf PROPERTIES
     VERSION ${protobuf_VERSION}
-    # Use only the first SO version component for compatibility with Makefile emitted SONAME.
     SOVERSION 30
     OUTPUT_NAME ${LIB_PREFIX}protobuf
     DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index ed20f31..317e4c2 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -131,6 +131,11 @@
 
 add_library(libprotoc ${protobuf_SHARED_OR_STATIC}
   ${libprotoc_files} ${libprotoc_headers} ${libprotoc_rc_files})
+if(protobuf_HAVE_LD_VERSION_SCRIPT)
+  target_link_options(libprotoc PRIVATE -Wl,--version-script=${protobuf_source_dir}/src/libprotoc.map)
+  set_target_properties(libprotoc PROPERTIES
+    LINK_DEPENDS ${protobuf_source_dir}/src/libprotoc.map)
+endif()
 target_link_libraries(libprotoc libprotobuf)
 if(MSVC AND protobuf_BUILD_SHARED_LIBS)
   target_compile_definitions(libprotoc
@@ -140,6 +145,7 @@
 set_target_properties(libprotoc PROPERTIES
     COMPILE_DEFINITIONS LIBPROTOC_EXPORTS
     VERSION ${protobuf_VERSION}
+    SOVERSION 30
     OUTPUT_NAME ${LIB_PREFIX}protoc
     DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
 add_library(protobuf::libprotoc ALIAS libprotoc)
diff --git a/configure.ac b/configure.ac
index 4c774b0..db69069 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,7 +80,7 @@
 ACX_USE_SYSTEM_EXTENSIONS
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc
-AC_PROG_OBJC
+AS_CASE([$target_os], [darwin*], [AC_PROG_OBJC], [AM_CONDITIONAL([am__fastdepOBJC], [false])])
 
 # test_util.cc takes forever to compile with GCC and optimization turned on.
 AC_MSG_CHECKING([C++ compiler flags...])
diff --git a/java/core/BUILD b/java/core/BUILD
index cf4ae7c..011fb1c 100644
--- a/java/core/BUILD
+++ b/java/core/BUILD
@@ -281,7 +281,7 @@
         "@maven//:com_google_guava_guava",
         "@maven//:com_google_truth_truth",
         "@maven//:junit_junit",
-        "@maven//:org_easymock_easymock",
+        "@maven//:org_mockito_mockito_core",
     ],
 )
 
@@ -408,6 +408,6 @@
         ":test_util_lite",
         "@maven//:com_google_truth_truth",
         "@maven//:junit_junit",
-        "@maven//:org_easymock_easymock",
+        "@maven//:org_mockito_mockito_core",
     ],
 )
diff --git a/java/core/pom.xml b/java/core/pom.xml
index ce068ee..07d88a0 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -23,8 +23,8 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index 5d2ee7f..b32a8b5 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -1554,10 +1554,6 @@
   public static class Parser {
     private int debugStringSilentMarker;
 
-    int getSilentMarkerCount() {
-      return debugStringSilentMarker;
-    }
-
     /**
      * A valid silent marker appears between a field name and its value. If there is a ":" in
      * between, the silent marker will only appear after the colon. This is called after a field
diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml
index 490fbb2..0637e6f 100644
--- a/java/kotlin-lite/pom.xml
+++ b/java/kotlin-lite/pom.xml
@@ -31,8 +31,8 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml
index 0f6feb2..d78456b 100644
--- a/java/kotlin/pom.xml
+++ b/java/kotlin/pom.xml
@@ -30,8 +30,8 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index c19d596..ce1d807 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -23,8 +23,8 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/java/pom.xml b/java/pom.xml
index e102597..e11bfe2 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -79,9 +79,9 @@
         <scope>test</scope>
       </dependency>
       <dependency>
-        <groupId>org.easymock</groupId>
-        <artifactId>easymock</artifactId>
-        <version>3.2</version>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-core</artifactId>
+        <version>4.3.1</version>
         <scope>test</scope>
       </dependency>
       <dependency>
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 27c82be..82b5d0a 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -52,8 +52,8 @@
       <artifactId>junit</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 85b377a..a2d18bc 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -1319,11 +1319,11 @@
         if (e.getCause() instanceof IOException) {
           throw (IOException) e.getCause();
         } else {
-          throw new InvalidProtocolBufferException(e.getMessage());
+          throw new InvalidProtocolBufferException(e.getMessage(), e);
         }
       } catch (RuntimeException e) {
         // We convert all exceptions from JSON parsing to our own exceptions.
-        throw new InvalidProtocolBufferException(e.getMessage());
+        throw new InvalidProtocolBufferException(e.getMessage(), e);
       }
     }
 
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index 7be94dc..2169690 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -34,6 +34,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.gson.JsonSyntaxException;
 import com.google.protobuf.Any;
 import com.google.protobuf.BoolValue;
 import com.google.protobuf.ByteString;
@@ -1861,7 +1862,7 @@
 
   // Test that we are not leaking out JSON exceptions.
   @Test
-  public void testJsonException() throws Exception {
+  public void testJsonException_forwardsIOException() throws Exception {
     InputStream throwingInputStream =
         new InputStream() {
           @Override
@@ -1879,7 +1880,10 @@
     } catch (IOException e) {
       assertThat(e).hasMessageThat().isEqualTo("12345");
     }
+  }
 
+  @Test
+  public void testJsonException_forwardsJsonException() throws Exception {
     Reader invalidJsonReader = new StringReader("{ xxx - yyy }");
     // When the JSON parser throws parser exceptions, JsonFormat should turn
     // that into InvalidProtocolBufferException.
@@ -1888,7 +1892,7 @@
       JsonFormat.parser().merge(invalidJsonReader, builder);
       assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
-      // Expected.
+      assertThat(e.getCause()).isInstanceOf(JsonSyntaxException.class);
     }
   }
 
diff --git a/maven_install.json b/maven_install.json
index bce3e2b..808e013 100644
--- a/maven_install.json
+++ b/maven_install.json
@@ -1,26 +1,14 @@
 {
     "dependency_tree": {
         "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
-        "__INPUT_ARTIFACTS_HASH": 1634601905,
-        "__RESOLVED_ARTIFACTS_HASH": -143733866,
+        "__INPUT_ARTIFACTS_HASH": -1867950668,
+        "__RESOLVED_ARTIFACTS_HASH": 1254982283,
         "conflict_resolution": {
             "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1",
             "junit:junit:4.12": "junit:junit:4.13.2"
         },
         "dependencies": [
             {
-                "coord": "cglib:cglib-nodep:2.2.2",
-                "dependencies": [],
-                "directDependencies": [],
-                "file": "v1/https/repo1.maven.org/maven2/cglib/cglib-nodep/2.2.2/cglib-nodep-2.2.2.jar",
-                "mirror_urls": [
-                    "https://repo1.maven.org/maven2/cglib/cglib-nodep/2.2.2/cglib-nodep-2.2.2.jar",
-                    "https://repo.maven.apache.org/maven2/cglib/cglib-nodep/2.2.2/cglib-nodep-2.2.2.jar"
-                ],
-                "sha256": "e78c7792e59554ed8a23d18a12e3a0d2f7a244217ecf89621477f63aec074f15",
-                "url": "https://repo1.maven.org/maven2/cglib/cglib-nodep/2.2.2/cglib-nodep-2.2.2.jar"
-            },
-            {
                 "coord": "com.google.auto.value:auto-value-annotations:1.7.4",
                 "dependencies": [],
                 "directDependencies": [],
@@ -83,21 +71,21 @@
             {
                 "coord": "com.google.guava:guava-testlib:30.1.1-jre",
                 "dependencies": [
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:failureaccess:1.0.1",
+                    "com.google.guava:guava:30.1.1-jre",
                     "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
                     "com.google.j2objc:j2objc-annotations:1.3",
-                    "com.google.code.findbugs:jsr305:3.0.2",
-                    "org.hamcrest:hamcrest-core:1.3",
-                    "com.google.guava:guava:30.1.1-jre",
-                    "com.google.guava:failureaccess:1.0.1",
-                    "com.google.errorprone:error_prone_annotations:2.5.1",
                     "junit:junit:4.13.2",
-                    "org.checkerframework:checker-qual:3.9.1"
+                    "org.checkerframework:checker-qual:3.9.1",
+                    "org.hamcrest:hamcrest-core:1.3"
                 ],
                 "directDependencies": [
-                    "com.google.j2objc:j2objc-annotations:1.3",
                     "com.google.code.findbugs:jsr305:3.0.2",
-                    "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:guava:30.1.1-jre",
+                    "com.google.j2objc:j2objc-annotations:1.3",
                     "junit:junit:4.13.2",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
@@ -112,19 +100,19 @@
             {
                 "coord": "com.google.guava:guava:30.1.1-jre",
                 "dependencies": [
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:failureaccess:1.0.1",
                     "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
                     "com.google.j2objc:j2objc-annotations:1.3",
-                    "com.google.code.findbugs:jsr305:3.0.2",
-                    "com.google.guava:failureaccess:1.0.1",
-                    "com.google.errorprone:error_prone_annotations:2.5.1",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "directDependencies": [
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:failureaccess:1.0.1",
                     "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
                     "com.google.j2objc:j2objc-annotations:1.3",
-                    "com.google.code.findbugs:jsr305:3.0.2",
-                    "com.google.guava:failureaccess:1.0.1",
-                    "com.google.errorprone:error_prone_annotations:2.5.1",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar",
@@ -162,20 +150,20 @@
             {
                 "coord": "com.google.truth:truth:1.1.2",
                 "dependencies": [
-                    "org.ow2.asm:asm:9.0",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:guava:30.1.1-jre",
                     "junit:junit:4.13.2",
-                    "org.checkerframework:checker-qual:3.9.1"
+                    "org.checkerframework:checker-qual:3.9.1",
+                    "org.ow2.asm:asm:9.0"
                 ],
                 "directDependencies": [
-                    "org.ow2.asm:asm:9.0",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "com.google.guava:guava:30.1.1-jre",
                     "junit:junit:4.13.2",
-                    "org.checkerframework:checker-qual:3.9.1"
+                    "org.checkerframework:checker-qual:3.9.1",
+                    "org.ow2.asm:asm:9.0"
                 ],
                 "file": "v1/https/repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar",
                 "mirror_urls": [
@@ -202,6 +190,30 @@
                 "url": "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
             },
             {
+                "coord": "net.bytebuddy:byte-buddy-agent:1.12.7",
+                "dependencies": [],
+                "directDependencies": [],
+                "file": "v1/https/repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.12.7/byte-buddy-agent-1.12.7.jar",
+                "mirror_urls": [
+                    "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.12.7/byte-buddy-agent-1.12.7.jar",
+                    "https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.12.7/byte-buddy-agent-1.12.7.jar"
+                ],
+                "sha256": "73d84bb6e8e8980e674d796a29063f510ceb527c6f8c912a08a13e236be05c71",
+                "url": "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.12.7/byte-buddy-agent-1.12.7.jar"
+            },
+            {
+                "coord": "net.bytebuddy:byte-buddy:1.12.7",
+                "dependencies": [],
+                "directDependencies": [],
+                "file": "v1/https/repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.12.7/byte-buddy-1.12.7.jar",
+                "mirror_urls": [
+                    "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.12.7/byte-buddy-1.12.7.jar",
+                    "https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.12.7/byte-buddy-1.12.7.jar"
+                ],
+                "sha256": "d2e46555699e70361b5471a7e142f9c67855bba6907a285177ebd8ad973775d8",
+                "url": "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.12.7/byte-buddy-1.12.7.jar"
+            },
+            {
                 "coord": "org.checkerframework:checker-qual:3.9.1",
                 "dependencies": [],
                 "directDependencies": [],
@@ -214,24 +226,6 @@
                 "url": "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.9.1/checker-qual-3.9.1.jar"
             },
             {
-                "coord": "org.easymock:easymock:3.2",
-                "dependencies": [
-                    "cglib:cglib-nodep:2.2.2",
-                    "org.objenesis:objenesis:1.3"
-                ],
-                "directDependencies": [
-                    "cglib:cglib-nodep:2.2.2",
-                    "org.objenesis:objenesis:1.3"
-                ],
-                "file": "v1/https/repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar",
-                "mirror_urls": [
-                    "https://repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar",
-                    "https://repo.maven.apache.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar"
-                ],
-                "sha256": "b3dd1cf5019f942d8cc2afad0aa6aef4b21532446fe90a6b68d567e3389763dd",
-                "url": "https://repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar"
-            },
-            {
                 "coord": "org.hamcrest:hamcrest-core:1.3",
                 "dependencies": [],
                 "directDependencies": [],
@@ -244,16 +238,36 @@
                 "url": "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"
             },
             {
-                "coord": "org.objenesis:objenesis:1.3",
+                "coord": "org.mockito:mockito-core:4.3.1",
+                "dependencies": [
+                    "net.bytebuddy:byte-buddy-agent:1.12.7",
+                    "net.bytebuddy:byte-buddy:1.12.7",
+                    "org.objenesis:objenesis:3.2"
+                ],
+                "directDependencies": [
+                    "net.bytebuddy:byte-buddy-agent:1.12.7",
+                    "net.bytebuddy:byte-buddy:1.12.7",
+                    "org.objenesis:objenesis:3.2"
+                ],
+                "file": "v1/https/repo1.maven.org/maven2/org/mockito/mockito-core/4.3.1/mockito-core-4.3.1.jar",
+                "mirror_urls": [
+                    "https://repo1.maven.org/maven2/org/mockito/mockito-core/4.3.1/mockito-core-4.3.1.jar",
+                    "https://repo.maven.apache.org/maven2/org/mockito/mockito-core/4.3.1/mockito-core-4.3.1.jar"
+                ],
+                "sha256": "148de2c6928365db29443ca12d35c930d9f481172b934fdd801d1cb1409ea83a",
+                "url": "https://repo1.maven.org/maven2/org/mockito/mockito-core/4.3.1/mockito-core-4.3.1.jar"
+            },
+            {
+                "coord": "org.objenesis:objenesis:3.2",
                 "dependencies": [],
                 "directDependencies": [],
-                "file": "v1/https/repo1.maven.org/maven2/org/objenesis/objenesis/1.3/objenesis-1.3.jar",
+                "file": "v1/https/repo1.maven.org/maven2/org/objenesis/objenesis/3.2/objenesis-3.2.jar",
                 "mirror_urls": [
-                    "https://repo1.maven.org/maven2/org/objenesis/objenesis/1.3/objenesis-1.3.jar",
-                    "https://repo.maven.apache.org/maven2/org/objenesis/objenesis/1.3/objenesis-1.3.jar"
+                    "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.2/objenesis-3.2.jar",
+                    "https://repo.maven.apache.org/maven2/org/objenesis/objenesis/3.2/objenesis-3.2.jar"
                 ],
-                "sha256": "dd4ef3d3091063a4fec578cbb2bbe6c1f921c00091ba2993dcd9afd25ff9444a",
-                "url": "https://repo1.maven.org/maven2/org/objenesis/objenesis/1.3/objenesis-1.3.jar"
+                "sha256": "03d960bd5aef03c653eb000413ada15eb77cdd2b8e4448886edf5692805e35f3",
+                "url": "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.2/objenesis-3.2.jar"
             },
             {
                 "coord": "org.ow2.asm:asm:9.0",
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index 27b8bee..2bee1b7 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -11,7 +11,7 @@
     "com.google.guava:guava-testlib:30.1.1-jre",
     "com.google.truth:truth:1.1.2",
     "junit:junit:4.12",
-    "org.easymock:easymock:3.2",
+    "org.mockito:mockito-core:4.3.1",
 ]
 
 def protobuf_deps():
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 62b4307..911372a 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -1235,21 +1235,25 @@
       for enum in desc.enum_types:
         yield (_PrefixWithDot(enum.full_name), enum)
 
-  def _GetDeps(self, dependencies):
+  def _GetDeps(self, dependencies, visited=None):
     """Recursively finds dependencies for file protos.
 
     Args:
       dependencies: The names of the files being depended on.
+      visited: The names of files already found.
 
     Yields:
       Each direct and indirect dependency.
     """
 
+    visited = visited or set()
     for dependency in dependencies:
-      dep_desc = self.FindFileByName(dependency)
-      yield dep_desc
-      for parent_dep in dep_desc.dependencies:
-        yield parent_dep
+      if dependency not in visited:
+        visited.add(dependency)
+        dep_desc = self.FindFileByName(dependency)
+        yield dep_desc
+        public_files = [d.name for d in dep_desc.public_dependencies]
+        yield from self._GetDeps(public_files, visited)
 
   def _GetTypeFromScope(self, package, type_name, scope):
     """Finds a given type name in the current scope.
diff --git a/python/google/protobuf/internal/import_test.py b/python/google/protobuf/internal/import_test.py
new file mode 100644
index 0000000..b5c572c
--- /dev/null
+++ b/python/google/protobuf/internal/import_test.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unittest for nested public imports."""
+
+import unittest
+
+from google.protobuf.internal.import_test_package import outer_pb2
+
+
+class ImportTest(unittest.TestCase):
+
+  def testPackageInitializationImport(self):
+    """Test that we can import nested import public messages."""
+
+    msg = outer_pb2.Outer()
+    self.assertEqual(58, msg.import_public_nested.value)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/import_test_package/import_public.proto b/python/google/protobuf/internal/import_test_package/import_public.proto
new file mode 100644
index 0000000..8774702
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/import_public.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A proto file which is imported by inner.proto to test public importing.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+option optimize_for = SPEED;
+
+// Test nested public import
+import public "google/protobuf/internal/import_test_package/import_public_nested.proto";
diff --git a/python/google/protobuf/internal/import_test_package/import_public_nested.proto b/python/google/protobuf/internal/import_test_package/import_public_nested.proto
new file mode 100644
index 0000000..fcf4d68
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/import_public_nested.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A proto file which is imported by import_public.proto to test nested public
+// importing.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+message ImportPublicNestedMessage {
+  optional int32 value = 1 [default = 58];
+}
diff --git a/python/google/protobuf/internal/import_test_package/inner.proto b/python/google/protobuf/internal/import_test_package/inner.proto
index 2887c12..f20c22e 100644
--- a/python/google/protobuf/internal/import_test_package/inner.proto
+++ b/python/google/protobuf/internal/import_test_package/inner.proto
@@ -32,6 +32,9 @@
 
 package google.protobuf.python.internal.import_test_package;
 
+// Test public import
+import public "google/protobuf/internal/import_test_package/import_public.proto";
+
 message Inner {
   optional int32 value = 1 [default = 57];
 }
diff --git a/python/google/protobuf/internal/import_test_package/outer.proto b/python/google/protobuf/internal/import_test_package/outer.proto
index a27fb5c..7810aec 100644
--- a/python/google/protobuf/internal/import_test_package/outer.proto
+++ b/python/google/protobuf/internal/import_test_package/outer.proto
@@ -36,4 +36,5 @@
 
 message Outer {
   optional Inner inner = 1;
+  optional ImportPublicNestedMessage import_public_nested = 2;
 }
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 5931aaa..920c17d 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -593,6 +593,7 @@
   if (std::numeric_limits<T>::min() == 0) {
     // Unsigned case.
     unsigned PY_LONG_LONG ulong_result = PyLong_AsUnsignedLongLong(arg_py_int);
+    Py_DECREF(arg_py_int);
     if (VerifyIntegerCastAndRange<T, unsigned PY_LONG_LONG>(arg,
                                                             ulong_result)) {
       *value = static_cast<T>(ulong_result);
@@ -601,6 +602,7 @@
     }
   } else {
     // Signed case.
+    Py_DECREF(arg_py_int);
     PY_LONG_LONG long_result = PyLong_AsLongLong(arg);
     if (VerifyIntegerCastAndRange<T, PY_LONG_LONG>(arg, long_result)) {
       *value = static_cast<T>(long_result);
diff --git a/src/Makefile.am b/src/Makefile.am
index 3331482..d53cf57 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -172,7 +172,6 @@
   google/protobuf/util/delimited_message_util.h                  \
   google/protobuf/util/field_comparator.h                        \
   google/protobuf/util/field_mask_util.h                         \
-  google/protobuf/util/internal/json_escaping.h                  \
   google/protobuf/util/json_util.h                               \
   google/protobuf/util/message_differencer.h                     \
   google/protobuf/util/time_util.h                               \
@@ -285,6 +284,7 @@
   google/protobuf/util/internal/field_mask_utility.cc          \
   google/protobuf/util/internal/field_mask_utility.h           \
   google/protobuf/util/internal/json_escaping.cc               \
+  google/protobuf/util/internal/json_escaping.h                \
   google/protobuf/util/internal/json_objectwriter.cc           \
   google/protobuf/util/internal/json_objectwriter.h            \
   google/protobuf/util/internal/json_stream_parser.cc          \
@@ -803,6 +803,12 @@
   google/protobuf/util/delimited_message_util_test.cc          \
   google/protobuf/util/field_comparator_test.cc                \
   google/protobuf/util/field_mask_util_test.cc                 \
+  google/protobuf/util/internal/default_value_objectwriter_test.cc \
+  google/protobuf/util/internal/json_objectwriter_test.cc      \
+  google/protobuf/util/internal/json_stream_parser_test.cc     \
+  google/protobuf/util/internal/protostream_objectsource_test.cc \
+  google/protobuf/util/internal/protostream_objectwriter_test.cc \
+  google/protobuf/util/internal/type_info_test_helper.cc       \
   google/protobuf/util/json_util_test.cc                       \
   google/protobuf/util/message_differencer_unittest.cc         \
   google/protobuf/util/time_util_test.cc                       \
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 6a713c4..d848831 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -522,6 +522,10 @@
   return StrCat("_", FieldName(field), "_cached_byte_size_");
 }
 
+// Note: A lot of libraries detect Any protos based on Descriptor::full_name()
+// while the two functions below use FileDescriptor::name(). In a sane world the
+// two approaches should be equivalent. But if you are dealing with descriptors
+// from untrusted sources, you might need to match semantics across libraries.
 bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
 bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index a076563..5051a97 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -200,7 +200,8 @@
   int max_has_bit_index_;
 
   // A map from field index to inlined_string index. For non-inlined-string
-  // fields, the element is -1.
+  // fields, the element is -1. If there is no inlined string in the message,
+  // this is empty.
   std::vector<int> inlined_string_indices_;
   // The count of inlined_string fields in the message.
   int max_inlined_string_index_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
index e9b48cd..f7dd629 100644
--- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
@@ -295,15 +295,9 @@
         "_fl::Offset{offsetof(", ClassName(descriptor), ", _oneof_case_)}"));
   }
 
-  int inlined_string_count = 0;
-  for (const FieldDescriptor* field : ordered_fields) {
-    if (IsString(field, options) && IsStringInlined(field, options)) {
-      ++inlined_string_count;
-    }
-  }
   // If this message has any inlined string fields, store the donation state
   // offset in the second auxiliary entry.
-  if (inlined_string_count > 0) {
+  if (!inlined_string_indices.empty()) {
     aux_entries.resize(2);  // pad if necessary
     aux_entries[1] =
         StrCat("_fl::Offset{offsetof(", ClassName(descriptor),
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index 2ed3b3a..2fb88b9 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -41,6 +41,7 @@
 #include <string>
 #include <utility>
 #include <vector>
+
 #include <google/protobuf/compiler/parser.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor_database.h>
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 1d4519c..0bb96ac 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -46,11 +46,11 @@
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/io/tokenizer.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/hash.h>
 
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 70fc436..7b42677 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -42,10 +42,10 @@
 #include <string>
 #include <utility>
 
-#include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/repeated_field.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/repeated_field.h>
 
 // Must be included last.
 #include <google/protobuf/port_def.inc>
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 5be4fa6..0524fd4 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -162,47 +162,45 @@
   return std::is_same<T, char>::value ? 8 : alignof(T);
 }
 
+template <int align, typename U, typename... T>
+using AppendIfAlign =
+    typename std::conditional<EffectiveAlignof<U>() == align, void (*)(T..., U),
+                              void (*)(T...)>::type;
+
 // Metafunction to sort types in descending order of alignment.
 // Useful for the flat allocator to ensure proper alignment of all elements
 // without having to add padding.
+// Instead of implementing a proper sort metafunction we just do a
+// filter+merge, which is much simpler to write as a metafunction.
+// We have a fixed set of alignments we can filter on.
 // For simplicity we use a function pointer as a type list.
-struct TypeListSorter {
-  template <int align, typename U, typename... T>
-  static auto AppendIfAlign(void (*)(T...)) ->
-      typename std::conditional<EffectiveAlignof<U>() == align,
-                                void (*)(T..., U), void (*)(T...)>::type {
-    return nullptr;
-  }
+template <typename In, typename T16, typename T8, typename T4, typename T2,
+          typename T1>
+struct TypeListSortImpl;
 
-  template <typename... T16, typename... T8, typename... T4, typename... T2,
-            typename... T1>
-  static auto SortImpl(void (*)(), void (*)(T16...), void (*)(T8...),
-                       void (*)(T4...), void (*)(T2...), void (*)(T1...))
-      -> void (*)(T16..., T8..., T4..., T2..., T1...) {
-    return nullptr;
-  }
-
-  template <typename T, typename... Ts, typename T16, typename T8, typename T4,
-            typename T2, typename T1, typename Self = TypeListSorter>
-  static auto SortImpl(void (*)(T, Ts...), T16 p16, T8 p8, T4 p4, T2 p2, T1 p1)
-      -> decltype(Self::template SortImpl(
-          static_cast<void (*)(Ts...)>(nullptr), AppendIfAlign<16, T>(p16),
-          AppendIfAlign<8, T>(p8), AppendIfAlign<4, T>(p4),
-          AppendIfAlign<2, T>(p2), AppendIfAlign<1, T>(p1))) {
-    return nullptr;
-  }
-
-  // Instead of implementing a proper sort metafunction we just do a
-  // filter+merge, which is much simpler to write as a metafunction.
-  // We have a fixed set of alignments we can filter on.
-  template <typename... T>
-  static auto SortByAlignment(void (*p)() = nullptr)
-      -> decltype(SortImpl(static_cast<void (*)(T...)>(nullptr), p, p, p, p,
-                           p)) {
-    return nullptr;
-  }
+template <typename... T16, typename... T8, typename... T4, typename... T2,
+          typename... T1>
+struct TypeListSortImpl<void (*)(), void (*)(T16...), void (*)(T8...),
+                        void (*)(T4...), void (*)(T2...), void (*)(T1...)> {
+  using type = void (*)(T16..., T8..., T4..., T2..., T1...);
 };
 
+template <typename First, typename... Rest, typename... T16, typename... T8,
+          typename... T4, typename... T2, typename... T1>
+struct TypeListSortImpl<void (*)(First, Rest...), void (*)(T16...),
+                        void (*)(T8...), void (*)(T4...), void (*)(T2...),
+                        void (*)(T1...)> {
+  using type = typename TypeListSortImpl<
+      void (*)(Rest...), AppendIfAlign<16, First, T16...>,
+      AppendIfAlign<8, First, T8...>, AppendIfAlign<4, First, T4...>,
+      AppendIfAlign<2, First, T2...>, AppendIfAlign<1, First, T1...>>::type;
+};
+
+template <typename... T>
+using SortByAlignment =
+    typename TypeListSortImpl<void (*)(T...), void (*)(), void (*)(),
+                              void (*)(), void (*)(), void (*)()>::type;
+
 template <template <typename...> class C, typename... T>
 auto ApplyTypeList(void (*)(T...)) -> C<T...>;
 
@@ -1239,12 +1237,12 @@
 // necessarily in the same order.
 class FlatAllocator
     : public decltype(ApplyTypeList<FlatAllocatorImpl>(
-          TypeListSorter::SortByAlignment<
-              char, std::string, SourceCodeInfo, FileDescriptorTables,
-              // Option types
-              MessageOptions, FieldOptions, EnumOptions, EnumValueOptions,
-              ExtensionRangeOptions, OneofOptions, ServiceOptions,
-              MethodOptions, FileOptions>())) {};
+          SortByAlignment<char, std::string, SourceCodeInfo,
+                          FileDescriptorTables,
+                          // Option types
+                          MessageOptions, FieldOptions, EnumOptions,
+                          EnumValueOptions, ExtensionRangeOptions, OneofOptions,
+                          ServiceOptions, MethodOptions, FileOptions>())) {};
 
 }  // namespace internal
 
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index c175a28..026b102 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -190,6 +190,7 @@
  public:
   constexpr ExtensionSet();
   explicit ExtensionSet(Arena* arena);
+  ExtensionSet(ArenaInitialized, Arena* arena) : ExtensionSet(arena) {}
   ~ExtensionSet();
 
   // These are called at startup by protocol-compiler-generated code to
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index 4e84b1b..d56a3f0 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -34,6 +34,7 @@
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_tctable_decl.h>
 #include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -1698,8 +1699,9 @@
       break;
     }
 
-    case field_layout::kRepIString:
-      break;  // note: skipped above
+    case field_layout::kRepIString: {
+      break;
+    }
   }
 
   if (ptr == nullptr || !is_valid) {
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 2d8129d..287d58f 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -502,6 +502,8 @@
   constexpr TypeDefinedMapFieldBase(ConstantInitialized tag)
       : MapFieldBase(tag) {}
   explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
+  TypeDefinedMapFieldBase(ArenaInitialized, Arena* arena)
+      : TypeDefinedMapFieldBase(arena) {}
 
  protected:
   ~TypeDefinedMapFieldBase() {}
@@ -574,6 +576,7 @@
       : TypeDefinedMapFieldBase<Key, T>(tag), impl_() {}
   explicit MapField(Arena* arena)
       : TypeDefinedMapFieldBase<Key, T>(arena), impl_(arena) {}
+  MapField(ArenaInitialized, Arena* arena) : MapField(arena) {}
 
   // Implement MapFieldBase
   bool ContainsMapKey(const MapKey& map_key) const override;
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index c114453..53bf7a0 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -70,6 +70,7 @@
 
   constexpr MapFieldLite() : map_() {}
   explicit MapFieldLite(Arena* arena) : map_(arena) {}
+  MapFieldLite(ArenaInitialized, Arena* arena) : MapFieldLite(arena) {}
 
 #ifdef NDEBUG
   void Destruct() { map_.~Map(); }
diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h
index 54f08db..a5c060b 100644
--- a/src/google/protobuf/port.h
+++ b/src/google/protobuf/port.h
@@ -58,12 +58,21 @@
 #endif
 }
 
-// Tag type used to invoke the constinit constructor overload of some classes.
-// Such constructors are internal implementation details of the library.
+// Tag type used to invoke the constinit constructor overload of classes
+// such as ArenaStringPtr and MapFieldBase. Such constructors are internal
+// implementation details of the library.
 struct ConstantInitialized {
   explicit ConstantInitialized() = default;
 };
 
+// Tag type used to invoke the arena constructor overload of classes such
+// as ExtensionSet and MapFieldLite in aggregate initialization. These
+// classes typically don't have move/copy constructors, which rules out
+// explicit initialization in pre-C++17.
+struct ArenaInitialized {
+  explicit ArenaInitialized() = default;
+};
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google