Merge release branch 22.x into main
diff --git a/.github/actions/bazel/action.yml b/.github/actions/bazel/action.yml
index 141527d..5fd3e9a 100644
--- a/.github/actions/bazel/action.yml
+++ b/.github/actions/bazel/action.yml
@@ -93,6 +93,29 @@
       shell: bash
       run: bazelisk version
 
+    # Bazel has multiple Xcode calls with hardcoded timeouts.  Many of these
+    # end up timing out on our github runners, causing flakes on every mac
+    # build that invoked Bazel.  To work around this, we manually inoke these
+    # calls before running Bazel to make sure they end up in Xcode's cache for
+    # quicker runs later.  All of these calls are obtained from xcrun calls in
+    # https://github.com/bazelbuild/bazel/blob/e8a69f5d5acaeb6af760631490ecbf73e8a04eeb/tools/cpp/osx_cc_configure.bzl.
+    # See https://github.com/bazelbuild/bazel/issues/17437 for more details.
+    # TODO(b/269503614) Remove this once Bazel provides an official solution.
+    - name: Warm up Xcode
+      if: ${{ runner.os == 'macOS' }}
+      shell: bash
+      run: |
+        mkdir -p mac_bazel_workaround
+        bazelisk ${{ steps.bazel.outputs.bazel-startup-flags }} build @bazel_tools//tools/osx:xcode_locator.m $BAZEL_FLAGS
+        XCODE_LOCATOR_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -fobjc-arc -framework CoreServices -framework Foundation"
+        SINGLE_ARCH_COMPILE_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -std=c++11 -lc++ -O3"
+        COMPILE_FLAGS="$SINGLE_ARCH_COMPILE_FLAGS -arch arm64 -arch x86_64 -Wl,-no_adhoc_codesign -Wl,-no_uuid -O3"
+        time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $XCODE_LOCATOR_FLAGS -o mac_bazel_workaround/xcode-locator-bin $(bazel info output_base)/external/bazel_tools/tools/osx/xcode_locator.m
+        time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
+        time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
+        time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
+        time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
+
     - name: Run Bash
       if: ${{ inputs.bash }}
       run: ${{ inputs.bash }}
diff --git a/.github/actions/internal/bazel-setup/action.yml b/.github/actions/internal/bazel-setup/action.yml
index 20e7241..0ef5d5a 100644
--- a/.github/actions/internal/bazel-setup/action.yml
+++ b/.github/actions/internal/bazel-setup/action.yml
@@ -42,7 +42,9 @@
     - name: Initialize MacOS-specific Bazel flags
       if: runner.os == 'macOS'
       shell: bash
-      run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --xcode_version_config=//.github:host_xcodes" >> $GITHUB_ENV
+      run: |
+        echo "BAZEL_FLAGS=$BAZEL_FLAGS --xcode_version_config=//.github:host_xcodes" >> $GITHUB_ENV
+        echo "DEVELOPER_DIR=${{ env.DEVELOPER_DIR || '/Applications/Xcode_14.1.app/Contents/Developer' }}" >> $GITHUB_ENV
 
     - name: Configure Bazel caching
       # Skip bazel cache for local act runs due to issue with credential files
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index e17f174..26b4a32 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -2,7 +2,16 @@
 # https://github.com/codespell-project/actions-codespell
 # https://github.com/codespell-project/codespell
 name: codespell
-on: [push, pull_request]
+on:
+  push:
+    branches:
+      - main
+      - '[0-9]+.x'
+  pull_request:
+    branches:
+      - main
+      - '[0-9]+.x'
+
 permissions:
   contents: read  #  to fetch code (actions/checkout)
 jobs:
diff --git a/.github/workflows/test_runner.yml b/.github/workflows/test_runner.yml
index a99d090..9fa37f1 100644
--- a/.github/workflows/test_runner.yml
+++ b/.github/workflows/test_runner.yml
@@ -41,7 +41,7 @@
     branches:
       - main
       - '[0-9]+.x'
-      # The 21.x branch still uses Kokoro
+      # The 21.x branch still use Kokoro
       - '!21.x'
       # For testing purposes so we can stage this on the `gha` branch.
       - gha
diff --git a/README.md b/README.md
index 3bfeb0f..c84ab2b 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,12 @@
 
 Copyright 2008 Google Inc.
 
-[Protocol Buffers documentation](https://developers.google.com/protocol-buffers/)
-
 Overview
 --------
 
 Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
 platform-neutral, extensible mechanism for serializing structured data. You
-can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
+can learn more about it in [protobuf's documentation](https://protobuf.dev).
 
 This README file contains protobuf installation instructions. To install
 protobuf, you need to install the protocol compiler (used to compile .proto
@@ -64,7 +62,7 @@
 -----------
 
 The best way to learn how to use protobuf is to follow the [tutorials in our
-developer guide](https://developers.google.com/protocol-buffers/docs/tutorials).
+developer guide](https://protobuf.dev/getting-started).
 
 If you want to learn from code examples, take a look at the examples in the
 [examples](examples) directory.
@@ -72,11 +70,16 @@
 Documentation
 -------------
 
-The complete documentation is available via the [Protocol Buffers documentation](https://developers.google.com/protocol-buffers/).
+The complete documentation is available at the [Protocol Buffers doc site](https://protobuf.dev).
+
+Support Policy
+--------------
+
+Read about our [version support policy](https://protobuf.dev/version-support/)
+to stay current on support timeframes for the language libraries.
 
 Developer Community
 -------------------
 
 To be alerted to upcoming changes in Protocol Buffers and connect with protobuf developers and users,
 [join the Google Group](https://groups.google.com/g/protobuf).
-
diff --git a/csharp/BUILD.bazel b/csharp/BUILD.bazel
index 23fbe41..2af7d06 100644
--- a/csharp/BUILD.bazel
+++ b/csharp/BUILD.bazel
@@ -65,9 +65,11 @@
     srcs = [
         ":srcs",
         "src/Google.Protobuf.sln",
+        "//conformance:conformance_csharp_proto",
         "//csharp/src/Google.Protobuf.Conformance:srcs",
     ],
     cmd = """
+        cp $(rootpath //conformance:conformance_csharp_proto) `dirname $(location src/Google.Protobuf.sln)`/Google.Protobuf.Conformance/
         pushd `dirname $(location src/Google.Protobuf.sln)`/..
         dotnet restore src/Google.Protobuf.sln
         dotnet build -c Release src/Google.Protobuf.sln
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
index cd682c2..17b1640 100755
--- a/csharp/generate_protos.sh
+++ b/csharp/generate_protos.sh
@@ -79,3 +79,8 @@
 $PROTOC -Iexamples -Isrc --csharp_out=csharp/src/AddressBook \
     --csharp_opt=file_extension=.pb.cs \
     examples/addressbook.proto
+
+# Conformance tests
+$PROTOC -I. --csharp_out=csharp/src/Google.Protobuf.Conformance \
+    --csharp_opt=file_extension=.pb.cs \
+    conformance/conformance.proto
diff --git a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
index 12ad0f7..0b5e2c8 100644
--- a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
+++ b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
@@ -1,3 +1,4 @@
+load("//:protobuf.bzl", "internal_csharp_proto_library")
 load("//build_defs:internal_shell.bzl", "inline_sh_binary")
 load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
 
@@ -37,7 +38,6 @@
 filegroup(
     name = "srcs",
     srcs = [
-        "Conformance.cs",
         "Program.cs",
         "Google.Protobuf.Conformance.csproj",
     ],
@@ -88,7 +88,6 @@
     srcs = [
         "BUILD.bazel",
         "Google.Protobuf.Conformance.csproj",
-        "Conformance.cs",
         "Program.cs",
     ],
     strip_prefix = strip_prefix.from_root(""),
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
similarity index 93%
rename from csharp/src/Google.Protobuf.Conformance/Conformance.cs
rename to csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
index 77fd9c9..664a17b 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
@@ -1,6 +1,6 @@
 // <auto-generated>
 //     Generated by the protocol buffer compiler.  DO NOT EDIT!
-//     source: conformance.proto
+//     source: conformance/conformance.proto
 // </auto-generated>
 #pragma warning disable 1591, 0612, 3021, 8981
 #region Designer generated code
@@ -11,11 +11,11 @@
 using scg = global::System.Collections.Generic;
 namespace Conformance {
 
-  /// <summary>Holder for reflection information generated from conformance.proto</summary>
+  /// <summary>Holder for reflection information generated from conformance/conformance.proto</summary>
   public static partial class ConformanceReflection {
 
     #region Descriptor
-    /// <summary>File descriptor for conformance.proto</summary>
+    /// <summary>File descriptor for conformance/conformance.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
@@ -24,34 +24,35 @@
     static ConformanceReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiHQoKRmFpbHVyZVNl",
-            "dBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
-            "cHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgCIAEo",
-            "CUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9hZBgI",
-            "IAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0GAMgASgOMhcuY29u",
-            "Zm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5cGUYBCABKAkSMAoN",
-            "dGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNlLlRlc3RDYXRlZ29y",
-            "eRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsyHy5jb25mb3JtYW5j",
-            "ZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5rbm93bl9maWVsZHMY",
-            "CSABKAhCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtw",
-            "YXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgA",
-            "EhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2Fk",
-            "GAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgF",
-            "IAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9h",
-            "ZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5jb2RpbmdDb25maWcSIQoZ",
-            "dXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEoCCpQCgpXaXJlRm9ybWF0",
-            "Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQARIICgRKU09OEAISCAoE",
-            "SlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRlc3RDYXRlZ29yeRIUChBV",
-            "TlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RFU1QQARINCglKU09OX1RF",
-            "U1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BBUlNJTkdfVEVTVBADEg0K",
-            "CUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RFU1QQBUIhCh9jb20uZ29v",
-            "Z2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90bzM="));
+            "Ch1jb25mb3JtYW5jZS9jb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2Ui",
+            "HQoKRmFpbHVyZVNldBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5j",
+            "ZVJlcXVlc3QSGgoQcHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25f",
+            "cGF5bG9hZBgCIAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRl",
+            "eHRfcGF5bG9hZBgIIAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0",
+            "GAMgASgOMhcuY29uZm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5",
+            "cGUYBCABKAkSMAoNdGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNl",
+            "LlRlc3RDYXRlZ29yeRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsy",
+            "Hy5jb25mb3JtYW5jZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5r",
+            "bm93bl9maWVsZHMYCSABKAhCCQoHcGF5bG9hZCL6AQoTQ29uZm9ybWFuY2VS",
+            "ZXNwb25zZRIVCgtwYXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9l",
+            "cnJvchgGIAEoCUgAEhcKDXRpbWVvdXRfZXJyb3IYCSABKAlIABIXCg1ydW50",
+            "aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgDIAEoDEgA",
+            "EhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSABKAlIABIW",
+            "Cgxqc3BiX3BheWxvYWQYByABKAlIABIWCgx0ZXh0X3BheWxvYWQYCCABKAlI",
+            "AEIICgZyZXN1bHQiNwoSSnNwYkVuY29kaW5nQ29uZmlnEiEKGXVzZV9qc3Bi",
+            "X2FycmF5X2FueV9mb3JtYXQYASABKAgqUAoKV2lyZUZvcm1hdBIPCgtVTlNQ",
+            "RUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoESlNPThACEggKBEpTUEIQAxIP",
+            "CgtURVhUX0ZPUk1BVBAEKo8BCgxUZXN0Q2F0ZWdvcnkSFAoQVU5TUEVDSUZJ",
+            "RURfVEVTVBAAEg8KC0JJTkFSWV9URVNUEAESDQoJSlNPTl9URVNUEAISJAog",
+            "SlNPTl9JR05PUkVfVU5LTk9XTl9QQVJTSU5HX1RFU1QQAxINCglKU1BCX1RF",
+            "U1QQBBIUChBURVhUX0ZPUk1BVF9URVNUEAVCLwofY29tLmdvb2dsZS5wcm90",
+            "b2J1Zi5jb25mb3JtYW5jZaICC0NvbmZvcm1hbmNlYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.TestCategory), }, null, new pbr::GeneratedClrTypeInfo[] {
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.FailureSet), global::Conformance.FailureSet.Parser, new[]{ "Failure" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions", "PrintUnknownFields" }, new[]{ "Payload" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "TimeoutError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.JspbEncodingConfig), global::Conformance.JspbEncodingConfig.Parser, new[]{ "UseJspbArrayAnyFormat" }, null, null, null, null)
           }));
     }
@@ -89,7 +90,8 @@
     /// </summary>
     [pbr::OriginalName("JSON_IGNORE_UNKNOWN_PARSING_TEST")] JsonIgnoreUnknownParsingTest = 3,
     /// <summary>
-    /// Test jspb wire format. Only used inside Google. Opensource testees just skip it.
+    /// Test jspb wire format. Only used inside Google. Opensource testees just
+    /// skip it.
     /// </summary>
     [pbr::OriginalName("JSPB_TEST")] JspbTest = 4,
     /// <summary>
@@ -382,7 +384,7 @@
     /// <summary>Field number for the "jspb_payload" field.</summary>
     public const int JspbPayloadFieldNumber = 7;
     /// <summary>
-    /// Only used inside google.  Opensource testees just skip it.
+    /// Only used inside Google.  Opensource testees just skip it.
     /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -443,8 +445,8 @@
     private global::Conformance.TestCategory testCategory_ = global::Conformance.TestCategory.UnspecifiedTest;
     /// <summary>
     /// Each test is given a specific test category. Some category may need
-    /// specific support in testee programs. Refer to the definition of TestCategory
-    /// for more information.
+    /// specific support in testee programs. Refer to the definition of
+    /// TestCategory for more information.
     /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -892,6 +894,9 @@
         case ResultOneofCase.SerializeError:
           SerializeError = other.SerializeError;
           break;
+        case ResultOneofCase.TimeoutError:
+          TimeoutError = other.TimeoutError;
+          break;
         case ResultOneofCase.RuntimeError:
           RuntimeError = other.RuntimeError;
           break;
@@ -957,6 +962,23 @@
       }
     }
 
+    /// <summary>Field number for the "timeout_error" field.</summary>
+    public const int TimeoutErrorFieldNumber = 9;
+    /// <summary>
+    /// This should be set if the test program timed out.  The string should
+    /// provide more information about what the child process was doing when it
+    /// was killed.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public string TimeoutError {
+      get { return resultCase_ == ResultOneofCase.TimeoutError ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.TimeoutError;
+      }
+    }
+
     /// <summary>Field number for the "runtime_error" field.</summary>
     public const int RuntimeErrorFieldNumber = 2;
     /// <summary>
@@ -1061,6 +1083,7 @@
       None = 0,
       ParseError = 1,
       SerializeError = 6,
+      TimeoutError = 9,
       RuntimeError = 2,
       ProtobufPayload = 3,
       JsonPayload = 4,
@@ -1099,6 +1122,7 @@
       }
       if (ParseError != other.ParseError) return false;
       if (SerializeError != other.SerializeError) return false;
+      if (TimeoutError != other.TimeoutError) return false;
       if (RuntimeError != other.RuntimeError) return false;
       if (ProtobufPayload != other.ProtobufPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
@@ -1115,6 +1139,7 @@
       int hash = 1;
       if (resultCase_ == ResultOneofCase.ParseError) hash ^= ParseError.GetHashCode();
       if (resultCase_ == ResultOneofCase.SerializeError) hash ^= SerializeError.GetHashCode();
+      if (resultCase_ == ResultOneofCase.TimeoutError) hash ^= TimeoutError.GetHashCode();
       if (resultCase_ == ResultOneofCase.RuntimeError) hash ^= RuntimeError.GetHashCode();
       if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
       if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
@@ -1172,6 +1197,10 @@
         output.WriteRawTag(66);
         output.WriteString(TextPayload);
       }
+      if (resultCase_ == ResultOneofCase.TimeoutError) {
+        output.WriteRawTag(74);
+        output.WriteString(TimeoutError);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -1214,6 +1243,10 @@
         output.WriteRawTag(66);
         output.WriteString(TextPayload);
       }
+      if (resultCase_ == ResultOneofCase.TimeoutError) {
+        output.WriteRawTag(74);
+        output.WriteString(TimeoutError);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(ref output);
       }
@@ -1230,6 +1263,9 @@
       if (resultCase_ == ResultOneofCase.SerializeError) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(SerializeError);
       }
+      if (resultCase_ == ResultOneofCase.TimeoutError) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TimeoutError);
+      }
       if (resultCase_ == ResultOneofCase.RuntimeError) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(RuntimeError);
       }
@@ -1267,6 +1303,9 @@
         case ResultOneofCase.SerializeError:
           SerializeError = other.SerializeError;
           break;
+        case ResultOneofCase.TimeoutError:
+          TimeoutError = other.TimeoutError;
+          break;
         case ResultOneofCase.RuntimeError:
           RuntimeError = other.RuntimeError;
           break;
@@ -1334,6 +1373,10 @@
             TextPayload = input.ReadString();
             break;
           }
+          case 74: {
+            TimeoutError = input.ReadString();
+            break;
+          }
         }
       }
     #endif
@@ -1381,6 +1424,10 @@
             TextPayload = input.ReadString();
             break;
           }
+          case 74: {
+            TimeoutError = input.ReadString();
+            break;
+          }
         }
       }
     }
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index ab9581a..b25011e 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -423,6 +423,26 @@
     return makeMutableCopy(list);
   }
 
+  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+  protected static LongList mutableCopy(LongList list) {
+    return makeMutableCopy(list);
+  }
+
+  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+  protected static FloatList mutableCopy(FloatList list) {
+    return makeMutableCopy(list);
+  }
+
+  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+  protected static DoubleList mutableCopy(DoubleList list) {
+    return makeMutableCopy(list);
+  }
+
+  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+  protected static BooleanList mutableCopy(BooleanList list) {
+    return makeMutableCopy(list);
+  }
+
   protected static LongList emptyLongList() {
     return LongArrayList.emptyList();
   }
@@ -432,11 +452,6 @@
     return new LongArrayList();
   }
 
-  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
-  protected static LongList mutableCopy(LongList list) {
-    return makeMutableCopy(list);
-  }
-
   protected static FloatList emptyFloatList() {
     return FloatArrayList.emptyList();
   }
@@ -446,11 +461,6 @@
     return new FloatArrayList();
   }
 
-  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
-  protected static FloatList mutableCopy(FloatList list) {
-    return makeMutableCopy(list);
-  }
-
   protected static DoubleList emptyDoubleList() {
     return DoubleArrayList.emptyList();
   }
@@ -460,11 +470,6 @@
     return new DoubleArrayList();
   }
 
-  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
-  protected static DoubleList mutableCopy(DoubleList list) {
-    return makeMutableCopy(list);
-  }
-
   protected static BooleanList emptyBooleanList() {
     return BooleanArrayList.emptyList();
   }
@@ -474,11 +479,6 @@
     return new BooleanArrayList();
   }
 
-  // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
-  protected static BooleanList mutableCopy(BooleanList list) {
-    return makeMutableCopy(list);
-  }
-
   @SuppressWarnings("unchecked") // Guaranteed by proto runtime.
   protected static <ListT extends ProtobufList<?>> ListT makeMutableCopy(ListT list) {
     int size = list.size();
diff --git a/objectivec/BUILD.bazel b/objectivec/BUILD.bazel
index 1c45357..0965de5 100644
--- a/objectivec/BUILD.bazel
+++ b/objectivec/BUILD.bazel
@@ -1,20 +1,66 @@
 load("@rules_cc//cc:defs.bzl", "objc_library")
 load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
+load("@upb//cmake:build_defs.bzl", "staleness_test")
 load("//conformance:defs.bzl", "conformance_test")
+load(":defs.bzl", "objc_proto_camel_case_name")
+
+# The WKTs have to be checked in to support the CocoaPods and Xcode builds. This
+# generule and test ensure the source are current.
+#
+# Within the ":objectivec" target, the outputs of the genrule are then used to
+# ensure they are always "current". This implementation is basically the same
+# has how the WKTs are handled in src/google/protobuf/BUILD.bazel for the C++
+# version. They share the potential downsides around layer checks and that
+# someone could #include the header with the `wkt/` prefix on the name.
+
+_WELL_KNOWN_TYPES = [
+    "any",
+    "api",
+    "duration",
+    "empty",
+    "field_mask",
+    "source_context",
+    "struct",
+    "timestamp",
+    "type",
+    "wrappers",
+]
+
+_OBJC_WKT_NAMES = [objc_proto_camel_case_name(x) for x in _WELL_KNOWN_TYPES]
+
+_OBJC_EXTS = [
+    ".pbobjc.h",
+    ".pbobjc.m",
+]
+
+genrule(
+    name = "gen_wkt_sources",
+    srcs = ["//src/google/protobuf:well_known_type_protos"],
+    outs = ["wkt/GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+    cmd = " && ".join([
+        "$(execpath //:protoc) --objc_out=$(RULEDIR)/wkt --proto_path=src $(SRCS)",
+    ] + [
+        "mv $(RULEDIR)/wkt/google/protobuf/" + wkt + ext + " $(RULEDIR)/wkt/GPB" + wkt + ext
+        for wkt in _OBJC_WKT_NAMES
+        for ext in _OBJC_EXTS
+    ]),
+    exec_tools = ["//:protoc"],
+)
+
+staleness_test(
+    name = "well_known_types_staleness_test",
+    outs = ["GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+    generated_pattern = "wkt/%s",
+    tags = ["manual"],
+)
+
+################################################################################
+# Objective-C Runtime Library
+################################################################################
 
 objc_library(
     name = "objectivec",
     hdrs = [
-        "GPBAny.pbobjc.h",
-        "GPBApi.pbobjc.h",
-        "GPBDuration.pbobjc.h",
-        "GPBEmpty.pbobjc.h",
-        "GPBFieldMask.pbobjc.h",
-        "GPBSourceContext.pbobjc.h",
-        "GPBStruct.pbobjc.h",
-        "GPBTimestamp.pbobjc.h",
-        "GPBType.pbobjc.h",
-        "GPBWrappers.pbobjc.h",
         "GPBArray.h",
         "GPBBootstrap.h",
         "GPBCodedInputStream.h",
@@ -55,39 +101,30 @@
         "GPBUnknownFieldSet_PackagePrivate.h",
         "GPBUnknownField_PackagePrivate.h",
         "GPBUtilities_PackagePrivate.h",
-    ],
+    ] + ["wkt/GPB" + wkt + ".pbobjc.h" for wkt in _OBJC_WKT_NAMES],
     copts = [
         "-Wno-vla",
     ],
     includes = [
         ".",
+        "wkt",
     ],
     non_arc_srcs = [
-        "GPBAny.pbobjc.m",
-        "GPBApi.pbobjc.m",
         "GPBArray.m",
         "GPBCodedInputStream.m",
         "GPBCodedOutputStream.m",
         "GPBDescriptor.m",
         "GPBDictionary.m",
-        "GPBDuration.pbobjc.m",
-        "GPBEmpty.pbobjc.m",
         "GPBExtensionInternals.m",
         "GPBExtensionRegistry.m",
-        "GPBFieldMask.pbobjc.m",
         "GPBMessage.m",
         "GPBRootObject.m",
-        "GPBSourceContext.pbobjc.m",
-        "GPBStruct.pbobjc.m",
-        "GPBTimestamp.pbobjc.m",
-        "GPBType.pbobjc.m",
         "GPBUnknownField.m",
         "GPBUnknownFieldSet.m",
         "GPBUtilities.m",
         "GPBWellKnownTypes.m",
         "GPBWireFormat.m",
-        "GPBWrappers.pbobjc.m",
-    ],
+    ] + ["wkt/GPB" + wkt + ".pbobjc.m" for wkt in _OBJC_WKT_NAMES],
     target_compatible_with = select({
         "@platforms//os:macos": [],
         "@platforms//os:ios": [],
@@ -105,8 +142,8 @@
 conformance_test(
     name = "conformance_test",
     failure_list = "//conformance:failure_list_objc.txt",
-    testee = "//conformance:conformance_objc",
     target_compatible_with = ["@platforms//os:macos"],
+    testee = "//conformance:conformance_objc",
 )
 
 # -------------------------------------------------------------------
@@ -121,6 +158,34 @@
     ],
 )
 
+# -------------------------------------------------------------------
+# Validation of pddm expansion.
+
+py_binary(
+    name = "pddm",
+    srcs = ["DevTools/pddm.py"],
+)
+
+py_test(
+    name = "pddm_tests",
+    size = "small",
+    srcs = [
+        "DevTools/pddm.py",
+        "DevTools/pddm_tests.py",
+    ],
+)
+
+sh_test(
+    name = "sources_pddm_expansion_test",
+    size = "small",
+    srcs = ["DevTools/sources_pddm_expansion_test.sh"],
+    data = [":pddm"] + glob([
+        "**/*.h",
+        "**/*.m",
+        "**/*.pddm",
+    ]),
+)
+
 ################################################################################
 # Distribution files
 ################################################################################
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
index d091a95..16981f9 100755
--- a/objectivec/DevTools/full_mac_build.sh
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -2,8 +2,6 @@
 #
 # Helper to do build so you don't have to remember all the steps/args.
 
-echo "::group::Run full mac build"
-
 set -eu
 
 # Some base locations.
@@ -12,7 +10,7 @@
 readonly BazelFlags="${BAZEL_FLAGS:---announce_rc --macos_minimum_os=10.9}"
 
 # Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+readonly BazelBin="${BAZEL:-bazel}"
 
 printUsage() {
   NAME=$(basename "${0}")
@@ -29,9 +27,6 @@
          Show this message
    -c, --clean
          Issue a clean before the normal build.
-   -r, --regenerate-descriptors
-         Run generate_descriptor_proto.sh to regenerate all the checked in
-         proto sources.
    --full-build
          By default only protoc is built within protobuf, this option will
          enable a full build/test of the entire protobuf project.
@@ -76,7 +71,6 @@
 fi
 
 DO_CLEAN=no
-REGEN_DESCRIPTORS=no
 FULL_BUILD=no
 DO_XCODE_IOS_TESTS=yes
 DO_XCODE_OSX_TESTS=yes
@@ -94,9 +88,6 @@
     -c | --clean )
       DO_CLEAN=yes
       ;;
-    -r | --regenerate-descriptors )
-      REGEN_DESCRIPTORS=yes
-      ;;
     --full-build )
       FULL_BUILD=yes
       ;;
@@ -190,21 +181,16 @@
   fi
 fi
 
-if [[ "${REGEN_DESCRIPTORS}" == "yes" ]] ; then
-  header "Regenerating the descriptor sources."
-  ./generate_descriptor_proto.sh
-fi
-
 if [[ "${FULL_BUILD}" == "yes" ]] ; then
   header "Build/Test: everything"
-  time ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
+  ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
 else
   header "Building: protoc"
-  time ${BazelBin} build //:protoc $BazelFlags
+  ${BazelBin} build //:protoc $BazelFlags
 fi
 
 # Ensure the WKT sources checked in are current.
-time objectivec/generate_well_known_types.sh --check-only $BazelFlags
+objectivec/generate_well_known_types.sh --check-only
 
 header "Checking on the ObjC Runtime Code"
 # Some of the kokoro machines don't have python3 yet, so fall back to python if need be.
@@ -233,8 +219,7 @@
   if [[ "${XCODE_QUIET}" == "yes" ]] ; then
     XCODEBUILD_TEST_BASE_IOS+=( -quiet )
   fi
-  # Don't need to worry about form factors or retina/non retina;
-  # just pick a mix of OS Versions and 32/64 bit.
+  # Don't need to worry about form factors or retina/non retina.
   # NOTE: Different Xcode have different simulated hardware/os support.
   case "${XCODE_VERSION}" in
     [6-9].* | 1[0-2].* )
@@ -242,9 +227,8 @@
       exit 11
       ;;
     13.* | 14.*)
-      # Dropped 32bit as Apple doesn't seem support the simulators either.
       XCODEBUILD_TEST_BASE_IOS+=(
-          -destination "platform=iOS Simulator,name=iPhone 8,OS=latest" # 64bit
+          -destination "platform=iOS Simulator,name=iPhone 13,OS=latest"
       )
       ;;
     * )
@@ -271,8 +255,7 @@
     "${XCODEBUILD}"
       -project objectivec/ProtocolBuffers_OSX.xcodeproj
       -scheme ProtocolBuffers
-      # Since the ObjC 2.0 Runtime is required, 32bit OS X isn't supported.
-      -destination "platform=OS X,arch=x86_64" # 64bit
+      -destination "platform=macOS"
   )
   if [[ "${XCODE_QUIET}" == "yes" ]] ; then
     XCODEBUILD_TEST_BASE_OSX+=( -quiet )
@@ -331,10 +314,8 @@
 
 if [[ "${DO_OBJC_CONFORMANCE_TESTS}" == "yes" ]] ; then
   header "Running ObjC Conformance Tests"
-  time ${BazelBin} test //objectivec:conformance_test $BazelFlags
+  ${BazelBin} test //objectivec:conformance_test $BazelFlags
 fi
 
 echo ""
 echo "$(basename "${0}"): Success!"
-
-echo "::endgroup::"
diff --git a/objectivec/DevTools/sources_pddm_expansion_test.sh b/objectivec/DevTools/sources_pddm_expansion_test.sh
new file mode 100755
index 0000000..99e01a1
--- /dev/null
+++ b/objectivec/DevTools/sources_pddm_expansion_test.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/pddm \
+  --dry-run \
+  ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/*.[hm] \
+  ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/Tests/*.[hm] \
+  || die "Update by running: objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]"
+
+echo "PASS"
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
index ad5c75e..9acf6f1 100644
--- a/objectivec/GPBCodedInputStream.m
+++ b/objectivec/GPBCodedInputStream.m
@@ -51,6 +51,10 @@
 //  int CodedInputStream::default_recursion_limit_ = 100;
 static const NSUInteger kDefaultRecursionLimit = 100;
 
+// Bytes and Strings have a max size of 2GB.
+// https://protobuf.dev/programming-guides/encoding/#cheat-sheet
+static const uint32_t kMaxFieldSize = 0x7fffffff;
+
 static void RaiseException(NSInteger code, NSString *reason) {
   NSDictionary *errorInfo = nil;
   if ([reason length]) {
@@ -223,14 +227,20 @@
 }
 
 NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state) {
-  int32_t size = ReadRawVarint32(state);
+  uint64_t size = GPBCodedInputStreamReadUInt64(state);
+  if (size > kMaxFieldSize) {
+    // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+    // so reuse an existing one.
+    RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+  }
+  NSUInteger ns_size = (NSUInteger)size;
   NSString *result;
   if (size == 0) {
     result = @"";
   } else {
     CheckSize(state, size);
     result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
-                                      length:size
+                                      length:ns_size
                                     encoding:NSUTF8StringEncoding];
     state->bufferPos += size;
     if (!result) {
@@ -246,21 +256,31 @@
 }
 
 NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
-  int32_t size = ReadRawVarint32(state);
-  if (size < 0) return nil;
+  uint64_t size = GPBCodedInputStreamReadUInt64(state);
+  if (size > kMaxFieldSize) {
+    // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+    // so reuse an existing one.
+    RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+  }
+  NSUInteger ns_size = (NSUInteger)size;
   CheckSize(state, size);
-  NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:size];
+  NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:ns_size];
   state->bufferPos += size;
   return result;
 }
 
 NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(GPBCodedInputStreamState *state) {
-  int32_t size = ReadRawVarint32(state);
-  if (size < 0) return nil;
+  uint64_t size = GPBCodedInputStreamReadUInt64(state);
+  if (size > kMaxFieldSize) {
+    // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+    // so reuse an existing one.
+    RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+  }
+  NSUInteger ns_size = (NSUInteger)size;
   CheckSize(state, size);
   // Cast is safe because freeWhenDone is NO.
   NSData *result = [[NSData alloc] initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
-                                                length:size
+                                                length:ns_size
                                           freeWhenDone:NO];
   state->bufferPos += size;
   return result;
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index 5b7ce0c..d9fc898 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -293,6 +293,10 @@
  *
  * @note This can raise the GPBCodedOutputStreamException_* exceptions.
  *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
  **/
 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
 
@@ -302,6 +306,11 @@
  * @param output The output stream into which to write the message.
  *
  * @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
  **/
 - (void)writeToOutputStream:(NSOutputStream *)output;
 
@@ -312,6 +321,11 @@
  * @param output The coded output stream into which to write the message.
  *
  * @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
  **/
 - (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
 
@@ -322,6 +336,11 @@
  * @param output The output stream into which to write the message.
  *
  * @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
  **/
 - (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
 
@@ -336,6 +355,11 @@
  * @note In DEBUG ONLY, the message is also checked for all required field,
  *       if one is missing, nil will be returned.
  *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
+ *
  * @return The binary representation of the message.
  **/
 - (nullable NSData *)data;
@@ -347,6 +371,11 @@
  * @note This value is not cached, so if you are using it repeatedly, it is
  *       recommended to keep a local copy.
  *
+ * @note The most common cause of this failing is from one thread calling this
+ *       while another thread has a reference to this message or a message used
+ *       within a field and that other thread mutating the message while this
+ *       serialization is taking place.
+ *
  * @return The binary representation of the size along with the message.
  **/
 - (NSData *)delimitedData;
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 3342179..cb8d70a 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -1308,9 +1308,12 @@
   @try {
     [self writeToCodedOutputStream:stream];
   } @catch (NSException *exception) {
-    // This really shouldn't happen. The only way writeToCodedOutputStream:
-    // could throw is if something in the library has a bug and the
-    // serializedSize was wrong.
+    // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+    // failed to match between computing the size and writing out the bytes. However, the more
+    // common cause is while one thread was writing out the data, some other thread had a reference
+    // to this message or a message used as a nested field, and that other thread mutated that
+    // message, causing the pre computed serializedSize to no longer match the final size after
+    // serialization. It is not safe to mutate a message while accessing it from another thread.
 #ifdef DEBUG
     NSLog(@"%@: Internal exception while building message data: %@", [self class], exception);
 #endif
@@ -1328,9 +1331,12 @@
   @try {
     [self writeDelimitedToCodedOutputStream:stream];
   } @catch (NSException *exception) {
-    // This really shouldn't happen.  The only way writeToCodedOutputStream:
-    // could throw is if something in the library has a bug and the
-    // serializedSize was wrong.
+    // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+    // failed to match between computing the size and writing out the bytes. However, the more
+    // common cause is while one thread was writing out the data, some other thread had a reference
+    // to this message or a message used as a nested field, and that other thread mutated that
+    // message, causing the pre computed serializedSize to no longer match the final size after
+    // serialization. It is not safe to mutate a message while accessing it from another thread.
 #ifdef DEBUG
     NSLog(@"%@: Internal exception while building message delimitedData: %@", [self class],
           exception);
@@ -1821,7 +1827,7 @@
 
 //%PDDM-EXPAND-END (18 expansions)
 
-// clang-format off
+      // clang-format on
   }
 }
 
@@ -1848,8 +1854,7 @@
   value = [autocreatedExtensionMap_ objectForKey:extension];
   if (!value) {
     // Auto create the message extensions to match normal fields.
-    value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
-                                                     extension);
+    value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self, extension);
 
     if (autocreatedExtensionMap_ == nil) {
       autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
@@ -1926,8 +1931,7 @@
   GPBExtensionDescriptor *descriptor = extension;
 
   if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
-    GPBMessage *autocreatedValue =
-        [[autocreatedExtensionMap_ objectForKey:extension] retain];
+    GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
     // Must remove from the map before calling GPBClearMessageAutocreator() so
     // that GPBClearMessageAutocreator() knows its safe to clear.
     [autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -1959,9 +1963,7 @@
   GPBBecomeVisibleToAutocreator(self);
 }
 
-- (void)setExtension:(GPBExtensionDescriptor *)extension
-               index:(NSUInteger)idx
-               value:(id)value {
+- (void)setExtension:(GPBExtensionDescriptor *)extension index:(NSUInteger)idx value:(id)value {
   CheckExtension(self, extension);
 
   if (!extension.repeated) {
@@ -1991,8 +1993,7 @@
 
 #pragma mark - mergeFrom
 
-- (void)mergeFromData:(NSData *)data
-    extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
+- (void)mergeFromData:(NSData *)data extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
   GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
   [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
   [input checkLastTagWas:0];
@@ -2008,9 +2009,6 @@
     return;
   }
   NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
-  if (data == nil) {
-    return;
-  }
   [self mergeFromData:data extensionRegistry:extensionRegistry];
   [data release];
 }
@@ -2024,35 +2022,30 @@
 + (instancetype)parseFromData:(NSData *)data
             extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
                         error:(NSError **)errorPtr {
-  return [[[self alloc] initWithData:data
-                   extensionRegistry:extensionRegistry
+  return [[[self alloc] initWithData:data extensionRegistry:extensionRegistry
                                error:errorPtr] autorelease];
 }
 
 + (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
                         extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
                                     error:(NSError **)errorPtr {
-  return
-      [[[self alloc] initWithCodedInputStream:input
-                            extensionRegistry:extensionRegistry
-                                        error:errorPtr] autorelease];
+  return [[[self alloc] initWithCodedInputStream:input
+                               extensionRegistry:extensionRegistry
+                                           error:errorPtr] autorelease];
 }
 
 #pragma mark - Parse Delimited From Data Support
 
 + (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
-                                 extensionRegistry:
-                                     (id<GPBExtensionRegistry>)extensionRegistry
+                                 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
                                              error:(NSError **)errorPtr {
   GPBMessage *message = [[[self alloc] init] autorelease];
   @try {
-    [message mergeDelimitedFromCodedInputStream:input
-                              extensionRegistry:extensionRegistry];
+    [message mergeDelimitedFromCodedInputStream:input extensionRegistry:extensionRegistry];
     if (errorPtr) {
       *errorPtr = nil;
     }
-  }
-  @catch (NSException *exception) {
+  } @catch (NSException *exception) {
     message = nil;
     if (errorPtr) {
       *errorPtr = ErrorFromException(exception);
@@ -2098,12 +2091,10 @@
     if (tag == GPBWireFormatMessageSetTypeIdTag) {
       typeId = GPBCodedInputStreamReadUInt32(state);
       if (typeId != 0) {
-        extension = [extensionRegistry extensionForDescriptor:[self descriptor]
-                                                  fieldNumber:typeId];
+        extension = [extensionRegistry extensionForDescriptor:[self descriptor] fieldNumber:typeId];
       }
     } else if (tag == GPBWireFormatMessageSetMessageTag) {
-      rawBytes =
-          [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
+      rawBytes = [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
     } else {
       if (![input skipField:tag]) {
         break;
@@ -2115,12 +2106,8 @@
 
   if (rawBytes != nil && typeId != 0) {
     if (extension != nil) {
-      GPBCodedInputStream *newInput =
-          [[GPBCodedInputStream alloc] initWithData:rawBytes];
-      ExtensionMergeFromInputStream(extension,
-                                    extension.packable,
-                                    newInput,
-                                    extensionRegistry,
+      GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
+      ExtensionMergeFromInputStream(extension, extension.packable, newInput, extensionRegistry,
                                     self);
       [newInput release];
     } else {
@@ -2142,9 +2129,8 @@
   int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
 
   GPBDescriptor *descriptor = [self descriptor];
-  GPBExtensionDescriptor *extension =
-      [extensionRegistry extensionForDescriptor:descriptor
-                                    fieldNumber:fieldNumber];
+  GPBExtensionDescriptor *extension = [extensionRegistry extensionForDescriptor:descriptor
+                                                                    fieldNumber:fieldNumber];
   if (extension == nil) {
     if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
       [self parseMessageSet:input extensionRegistry:extensionRegistry];
@@ -2152,23 +2138,14 @@
     }
   } else {
     if (extension.wireType == wireType) {
-      ExtensionMergeFromInputStream(extension,
-                                    extension.packable,
-                                    input,
-                                    extensionRegistry,
-                                    self);
+      ExtensionMergeFromInputStream(extension, extension.packable, input, extensionRegistry, self);
       return YES;
     }
     // Primitive, repeated types can be packed on unpacked on the wire, and are
     // parsed either way.
-    if ([extension isRepeated] &&
-        !GPBDataTypeIsObject(extension->description_->dataType) &&
+    if ([extension isRepeated] && !GPBDataTypeIsObject(extension->description_->dataType) &&
         (extension.alternateWireType == wireType)) {
-      ExtensionMergeFromInputStream(extension,
-                                    !extension.packable,
-                                    input,
-                                    extensionRegistry,
-                                    self);
+      ExtensionMergeFromInputStream(extension, !extension.packable, input, extensionRegistry, self);
       return YES;
     }
   }
@@ -2187,38 +2164,38 @@
 
 #pragma mark - MergeFromCodedInputStream Support
 
-static void MergeSingleFieldFromCodedInputStream(
-    GPBMessage *self, GPBFieldDescriptor *field,
-    GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+static void MergeSingleFieldFromCodedInputStream(GPBMessage *self, GPBFieldDescriptor *field,
+                                                 GPBCodedInputStream *input,
+                                                 id<GPBExtensionRegistry> extensionRegistry) {
   GPBDataType fieldDataType = GPBGetFieldDataType(field);
   switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                             \
-    case GPBDataType##NAME: {                                              \
-      TYPE val = GPBCodedInputStreamRead##NAME(&input->state_);            \
-      GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val);           \
-      break;                                                               \
-            }
-#define CASE_SINGLE_OBJECT(NAME)                                           \
-    case GPBDataType##NAME: {                                              \
-      id val = GPBCodedInputStreamReadRetained##NAME(&input->state_);      \
-      GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val);          \
-      break;                                                               \
-    }
-      CASE_SINGLE_POD(Bool, BOOL, Bool)
-      CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
-      CASE_SINGLE_POD(SFixed32, int32_t, Int32)
-      CASE_SINGLE_POD(Float, float, Float)
-      CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
-      CASE_SINGLE_POD(SFixed64, int64_t, Int64)
-      CASE_SINGLE_POD(Double, double, Double)
-      CASE_SINGLE_POD(Int32, int32_t, Int32)
-      CASE_SINGLE_POD(Int64, int64_t, Int64)
-      CASE_SINGLE_POD(SInt32, int32_t, Int32)
-      CASE_SINGLE_POD(SInt64, int64_t, Int64)
-      CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
-      CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
-      CASE_SINGLE_OBJECT(Bytes)
-      CASE_SINGLE_OBJECT(String)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                 \
+  case GPBDataType##NAME: {                                    \
+    TYPE val = GPBCodedInputStreamRead##NAME(&input->state_);  \
+    GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
+    break;                                                     \
+  }
+#define CASE_SINGLE_OBJECT(NAME)                                    \
+  case GPBDataType##NAME: {                                         \
+    id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
+    GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val);     \
+    break;                                                          \
+  }
+    CASE_SINGLE_POD(Bool, BOOL, Bool)
+    CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+    CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+    CASE_SINGLE_POD(Float, float, Float)
+    CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+    CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+    CASE_SINGLE_POD(Double, double, Double)
+    CASE_SINGLE_POD(Int32, int32_t, Int32)
+    CASE_SINGLE_POD(Int64, int64_t, Int64)
+    CASE_SINGLE_POD(SInt32, int32_t, Int32)
+    CASE_SINGLE_POD(SInt64, int64_t, Int64)
+    CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+    CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+    CASE_SINGLE_OBJECT(Bytes)
+    CASE_SINGLE_OBJECT(String)
 #undef CASE_SINGLE_POD
 #undef CASE_SINGLE_OBJECT
 
@@ -2226,8 +2203,7 @@
       if (GPBGetHasIvarField(self, field)) {
         // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
         // check again.
-        GPBMessage *message =
-            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
         [input readMessage:message extensionRegistry:extensionRegistry];
       } else {
         GPBMessage *message = [[field.msgClass alloc] init];
@@ -2241,16 +2217,11 @@
       if (GPBGetHasIvarField(self, field)) {
         // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
         // check again.
-        GPBMessage *message =
-            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
-        [input readGroup:GPBFieldNumber(field)
-                      message:message
-            extensionRegistry:extensionRegistry];
+        GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
       } else {
         GPBMessage *message = [[field.msgClass alloc] init];
-        [input readGroup:GPBFieldNumber(field)
-                      message:message
-            extensionRegistry:extensionRegistry];
+        [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
         GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
       }
       break;
@@ -2268,9 +2239,9 @@
   }  // switch
 }
 
-static void MergeRepeatedPackedFieldFromCodedInputStream(
-    GPBMessage *self, GPBFieldDescriptor *field,
-    GPBCodedInputStream *input) {
+static void MergeRepeatedPackedFieldFromCodedInputStream(GPBMessage *self,
+                                                         GPBFieldDescriptor *field,
+                                                         GPBCodedInputStream *input) {
   GPBDataType fieldDataType = GPBGetFieldDataType(field);
   GPBCodedInputStreamState *state = &input->state_;
   id genericArray = GetOrCreateArrayIvarWithField(self, field);
@@ -2278,25 +2249,25 @@
   size_t limit = GPBCodedInputStreamPushLimit(state, length);
   while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
     switch (fieldDataType) {
-#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE)      \
-     case GPBDataType##NAME: {                                \
-       TYPE val = GPBCodedInputStreamRead##NAME(state);       \
-       [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
-       break;                                                 \
-     }
-        CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
-        CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
-        CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
-        CASE_REPEATED_PACKED_POD(Float, float, Float)
-        CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
-        CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
-        CASE_REPEATED_PACKED_POD(Double, double, Double)
-        CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
-        CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
-        CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
-        CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
-        CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
-        CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
+#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE)   \
+  case GPBDataType##NAME: {                                \
+    TYPE val = GPBCodedInputStreamRead##NAME(state);       \
+    [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+    break;                                                 \
+  }
+      CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
+      CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
+      CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
+      CASE_REPEATED_PACKED_POD(Float, float, Float)
+      CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
+      CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
+      CASE_REPEATED_PACKED_POD(Double, double, Double)
+      CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
+      CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
+      CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
+      CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
+      CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
+      CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
 #undef CASE_REPEATED_PACKED_POD
 
       case GPBDataTypeBytes:
@@ -2309,7 +2280,7 @@
       case GPBDataTypeEnum: {
         int32_t val = GPBCodedInputStreamReadEnum(state);
         if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
-          [(GPBEnumArray*)genericArray addRawValue:val];
+          [(GPBEnumArray *)genericArray addRawValue:val];
         } else {
           GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
           [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2317,66 +2288,64 @@
         break;
       }
     }  // switch
-  }  // while(BytesUntilLimit() > 0)
+  }    // while(BytesUntilLimit() > 0)
   GPBCodedInputStreamPopLimit(state, limit);
 }
 
 static void MergeRepeatedNotPackedFieldFromCodedInputStream(
-    GPBMessage *self, GPBFieldDescriptor *field,
-    GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+    GPBMessage *self, GPBFieldDescriptor *field, GPBCodedInputStream *input,
+    id<GPBExtensionRegistry> extensionRegistry) {
   GPBCodedInputStreamState *state = &input->state_;
   id genericArray = GetOrCreateArrayIvarWithField(self, field);
   switch (GPBGetFieldDataType(field)) {
 #define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
-   case GPBDataType##NAME: {                                 \
-     TYPE val = GPBCodedInputStreamRead##NAME(state);        \
-     [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val];  \
-     break;                                                  \
-   }
-#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME)                \
-   case GPBDataType##NAME: {                                 \
-     id val = GPBCodedInputStreamReadRetained##NAME(state);  \
-     [(NSMutableArray*)genericArray addObject:val];          \
-     [val release];                                          \
-     break;                                                  \
-   }
-      CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
-      CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
-      CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
-      CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
-      CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
-      CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
-      CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
-      CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
-      CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
-      CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
-      CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
-      CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
-      CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
-      CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
-      CASE_REPEATED_NOT_PACKED_OBJECT(String)
+  case GPBDataType##NAME: {                                  \
+    TYPE val = GPBCodedInputStreamRead##NAME(state);         \
+    [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val];   \
+    break;                                                   \
+  }
+#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME)              \
+  case GPBDataType##NAME: {                                \
+    id val = GPBCodedInputStreamReadRetained##NAME(state); \
+    [(NSMutableArray *)genericArray addObject:val];        \
+    [val release];                                         \
+    break;                                                 \
+  }
+    CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
+    CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
+    CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
+    CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
+    CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
+    CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
+    CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
+    CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
+    CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
+    CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
+    CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
+    CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
+    CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
+    CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
+    CASE_REPEATED_NOT_PACKED_OBJECT(String)
 #undef CASE_REPEATED_NOT_PACKED_POD
 #undef CASE_NOT_PACKED_OBJECT
     case GPBDataTypeMessage: {
       GPBMessage *message = [[field.msgClass alloc] init];
       [input readMessage:message extensionRegistry:extensionRegistry];
-      [(NSMutableArray*)genericArray addObject:message];
+      [(NSMutableArray *)genericArray addObject:message];
       [message release];
       break;
     }
     case GPBDataTypeGroup: {
       GPBMessage *message = [[field.msgClass alloc] init];
-      [input readGroup:GPBFieldNumber(field)
-                    message:message
-          extensionRegistry:extensionRegistry];
-      [(NSMutableArray*)genericArray addObject:message];
+      [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
+      [(NSMutableArray *)genericArray addObject:message];
       [message release];
       break;
     }
     case GPBDataTypeEnum: {
       int32_t val = GPBCodedInputStreamReadEnum(state);
       if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
-        [(GPBEnumArray*)genericArray addRawValue:val];
+        [(GPBEnumArray *)genericArray addRawValue:val];
       } else {
         GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
         [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2406,30 +2375,28 @@
       if (GPBFieldTag(fieldDescriptor) == tag) {
         GPBFieldType fieldType = fieldDescriptor.fieldType;
         if (fieldType == GPBFieldTypeSingle) {
-          MergeSingleFieldFromCodedInputStream(self, fieldDescriptor,
-                                               input, extensionRegistry);
+          MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, input, extensionRegistry);
           // Well formed protos will only have a single field once, advance
           // the starting index to the next field.
           startingIndex += 1;
         } else if (fieldType == GPBFieldTypeRepeated) {
           if (fieldDescriptor.isPackable) {
-            MergeRepeatedPackedFieldFromCodedInputStream(
-                self, fieldDescriptor, input);
+            MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
             // Well formed protos will only have a repeated field that is
             // packed once, advance the starting index to the next field.
             startingIndex += 1;
           } else {
-            MergeRepeatedNotPackedFieldFromCodedInputStream(
-                self, fieldDescriptor, input, extensionRegistry);
+            MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+                                                            extensionRegistry);
           }
         } else {  // fieldType == GPBFieldTypeMap
           // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
           // point.
           id map = GetOrCreateMapIvarWithField(self, fieldDescriptor);
           [input readMapEntry:map
-            extensionRegistry:extensionRegistry
-                        field:fieldDescriptor
-                parentMessage:self];
+              extensionRegistry:extensionRegistry
+                          field:fieldDescriptor
+                  parentMessage:self];
         }
         merged = YES;
         break;
@@ -2450,14 +2417,13 @@
             (GPBFieldAlternateTag(fieldDescriptor) == tag)) {
           BOOL alternateIsPacked = !fieldDescriptor.isPackable;
           if (alternateIsPacked) {
-            MergeRepeatedPackedFieldFromCodedInputStream(
-                self, fieldDescriptor, input);
+            MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
             // Well formed protos will only have a repeated field that is
             // packed once, advance the starting index to the next field.
             startingIndex += 1;
           } else {
-            MergeRepeatedNotPackedFieldFromCodedInputStream(
-                self, fieldDescriptor, input, extensionRegistry);
+            MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+                                                            extensionRegistry);
           }
           merged = YES;
           break;
@@ -2472,9 +2438,7 @@
         // zero signals EOF / limit reached
         return;
       } else {
-        if (![self parseUnknownField:input
-                   extensionRegistry:extensionRegistry
-                                 tag:tag]) {
+        if (![self parseUnknownField:input extensionRegistry:extensionRegistry tag:tag]) {
           // it's an endgroup tag
           return;
         }
@@ -2489,8 +2453,7 @@
 - (void)mergeFrom:(GPBMessage *)other {
   Class selfClass = [self class];
   Class otherClass = [other class];
-  if (!([selfClass isSubclassOfClass:otherClass] ||
-        [otherClass isSubclassOfClass:selfClass])) {
+  if (!([selfClass isSubclassOfClass:otherClass] || [otherClass isSubclassOfClass:selfClass])) {
     [NSException raise:NSInvalidArgumentException
                 format:@"Classes must match %@ != %@", selfClass, otherClass];
   }
@@ -2512,39 +2475,32 @@
       GPBDataType fieldDataType = GPBGetFieldDataType(field);
       switch (fieldDataType) {
         case GPBDataTypeBool:
-          GPBSetBoolIvarWithFieldPrivate(
-              self, field, GPBGetMessageBoolField(other, field));
+          GPBSetBoolIvarWithFieldPrivate(self, field, GPBGetMessageBoolField(other, field));
           break;
         case GPBDataTypeSFixed32:
         case GPBDataTypeEnum:
         case GPBDataTypeInt32:
         case GPBDataTypeSInt32:
-          GPBSetInt32IvarWithFieldPrivate(
-              self, field, GPBGetMessageInt32Field(other, field));
+          GPBSetInt32IvarWithFieldPrivate(self, field, GPBGetMessageInt32Field(other, field));
           break;
         case GPBDataTypeFixed32:
         case GPBDataTypeUInt32:
-          GPBSetUInt32IvarWithFieldPrivate(
-              self, field, GPBGetMessageUInt32Field(other, field));
+          GPBSetUInt32IvarWithFieldPrivate(self, field, GPBGetMessageUInt32Field(other, field));
           break;
         case GPBDataTypeSFixed64:
         case GPBDataTypeInt64:
         case GPBDataTypeSInt64:
-          GPBSetInt64IvarWithFieldPrivate(
-              self, field, GPBGetMessageInt64Field(other, field));
+          GPBSetInt64IvarWithFieldPrivate(self, field, GPBGetMessageInt64Field(other, field));
           break;
         case GPBDataTypeFixed64:
         case GPBDataTypeUInt64:
-          GPBSetUInt64IvarWithFieldPrivate(
-              self, field, GPBGetMessageUInt64Field(other, field));
+          GPBSetUInt64IvarWithFieldPrivate(self, field, GPBGetMessageUInt64Field(other, field));
           break;
         case GPBDataTypeFloat:
-          GPBSetFloatIvarWithFieldPrivate(
-              self, field, GPBGetMessageFloatField(other, field));
+          GPBSetFloatIvarWithFieldPrivate(self, field, GPBGetMessageFloatField(other, field));
           break;
         case GPBDataTypeDouble:
-          GPBSetDoubleIvarWithFieldPrivate(
-              self, field, GPBGetMessageDoubleField(other, field));
+          GPBSetDoubleIvarWithFieldPrivate(self, field, GPBGetMessageDoubleField(other, field));
           break;
         case GPBDataTypeBytes:
         case GPBDataTypeString: {
@@ -2556,8 +2512,7 @@
         case GPBDataTypeGroup: {
           id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
           if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
-            GPBMessage *message =
-                GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+            GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
             [message mergeFrom:otherVal];
           } else {
             GPBMessage *message = [otherVal copy];
@@ -2565,27 +2520,23 @@
           }
           break;
         }
-      } // switch()
+      }  // switch()
     } else if (fieldType == GPBFieldTypeRepeated) {
       // In the case of a list, they need to be appended, and there is no
       // _hasIvar to worry about setting.
-      id otherArray =
-          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+      id otherArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
       if (otherArray) {
         GPBDataType fieldDataType = field->description_->dataType;
         if (GPBDataTypeIsObject(fieldDataType)) {
-          NSMutableArray *resultArray =
-              GetOrCreateArrayIvarWithField(self, field);
+          NSMutableArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
           [resultArray addObjectsFromArray:otherArray];
         } else if (fieldDataType == GPBDataTypeEnum) {
-          GPBEnumArray *resultArray =
-              GetOrCreateArrayIvarWithField(self, field);
+          GPBEnumArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
           [resultArray addRawValuesFromArray:otherArray];
         } else {
           // The array type doesn't matter, that all implement
           // -addValuesFromArray:.
-          GPBInt32Array *resultArray =
-              GetOrCreateArrayIvarWithField(self, field);
+          GPBInt32Array *resultArray = GetOrCreateArrayIvarWithField(self, field);
           [resultArray addValuesFromArray:otherArray];
         }
       }
@@ -2596,27 +2547,23 @@
       if (otherDict) {
         GPBDataType keyDataType = field.mapKeyDataType;
         GPBDataType valueDataType = field->description_->dataType;
-        if (GPBDataTypeIsObject(keyDataType) &&
-            GPBDataTypeIsObject(valueDataType)) {
-          NSMutableDictionary *resultDict =
-              GetOrCreateMapIvarWithField(self, field);
+        if (GPBDataTypeIsObject(keyDataType) && GPBDataTypeIsObject(valueDataType)) {
+          NSMutableDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
           [resultDict addEntriesFromDictionary:otherDict];
         } else if (valueDataType == GPBDataTypeEnum) {
           // The exact type doesn't matter, just need to know it is a
           // GPB*EnumDictionary.
-          GPBInt32EnumDictionary *resultDict =
-              GetOrCreateMapIvarWithField(self, field);
+          GPBInt32EnumDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
           [resultDict addRawEntriesFromDictionary:otherDict];
         } else {
           // The exact type doesn't matter, they all implement
           // -addEntriesFromDictionary:.
-          GPBInt32Int32Dictionary *resultDict =
-              GetOrCreateMapIvarWithField(self, field);
+          GPBInt32Int32Dictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
           [resultDict addEntriesFromDictionary:otherDict];
         }
       }
     }  // if (fieldType)..else if...else
-  }  // for(fields)
+  }    // for(fields)
 
   // Unknown fields.
   if (!unknownFields_) {
@@ -2632,8 +2579,7 @@
   }
 
   if (extensionMap_ == nil) {
-    extensionMap_ =
-        CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
+    extensionMap_ = CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
   } else {
     for (GPBExtensionDescriptor *extension in other->extensionMap_) {
       id otherValue = [other->extensionMap_ objectForKey:extension];
@@ -2671,8 +2617,7 @@
       }
 
       if (isMessageExtension && !extension.isRepeated) {
-        GPBMessage *autocreatedValue =
-            [[autocreatedExtensionMap_ objectForKey:extension] retain];
+        GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
         // Must remove from the map before calling GPBClearMessageAutocreator()
         // so that GPBClearMessageAutocreator() knows its safe to clear.
         [autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -2706,10 +2651,8 @@
       // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
       // the type doesn't really matter as the objects all support -count and
       // -isEqual:.
-      NSArray *resultMapOrArray =
-          GPBGetObjectIvarWithFieldNoAutocreate(self, field);
-      NSArray *otherMapOrArray =
-          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+      NSArray *resultMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      NSArray *otherMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
       // nil and empty are equal
       if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
         if (![resultMapOrArray isEqual:otherMapOrArray]) {
@@ -2787,9 +2730,9 @@
           }
           break;
         }
-      } // switch()
-    }   // if(mapOrArray)...else
-  }  // for(fields)
+      }  // switch()
+    }    // if(mapOrArray)...else
+  }      // for(fields)
 
   // nil and empty are equal
   if (extensionMap_.count != 0 || otherMsg->extensionMap_.count != 0) {
@@ -2800,8 +2743,7 @@
 
   // nil and empty are equal
   GPBUnknownFieldSet *otherUnknowns = otherMsg->unknownFields_;
-  if ([unknownFields_ countOfFields] != 0 ||
-      [otherUnknowns countOfFields] != 0) {
+  if ([unknownFields_ countOfFields] != 0 || [otherUnknowns countOfFields] != 0) {
     if (![unknownFields_ isEqual:otherUnknowns]) {
       return NO;
     }
@@ -2904,7 +2846,7 @@
           result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
           break;
         }
-      } // switch()
+      }  // switch()
     }
   }
 
@@ -2917,8 +2859,8 @@
 
 - (NSString *)description {
   NSString *textFormat = GPBTextFormatForMessage(self, @"    ");
-  NSString *description = [NSString
-      stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
+  NSString *description =
+      [NSString stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
   return description;
 }
 
@@ -2956,44 +2898,43 @@
       uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
 
       switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                                \
-        case GPBDataType##NAME: {                                             \
-          TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
-          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
-          break;                                                              \
-        }
-#define CASE_SINGLE_OBJECT(NAME)                                              \
-        case GPBDataType##NAME: {                                             \
-          id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
-          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
-          break;                                                              \
-        }
-          CASE_SINGLE_POD(Bool, BOOL, Bool)
-          CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
-          CASE_SINGLE_POD(SFixed32, int32_t, Int32)
-          CASE_SINGLE_POD(Float, float, Float)
-          CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
-          CASE_SINGLE_POD(SFixed64, int64_t, Int64)
-          CASE_SINGLE_POD(Double, double, Double)
-          CASE_SINGLE_POD(Int32, int32_t, Int32)
-          CASE_SINGLE_POD(Int64, int64_t, Int64)
-          CASE_SINGLE_POD(SInt32, int32_t, Int32)
-          CASE_SINGLE_POD(SInt64, int64_t, Int64)
-          CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
-          CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
-          CASE_SINGLE_OBJECT(Bytes)
-          CASE_SINGLE_OBJECT(String)
-          CASE_SINGLE_OBJECT(Message)
-          CASE_SINGLE_OBJECT(Group)
-          CASE_SINGLE_POD(Enum, int32_t, Int32)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                              \
+  case GPBDataType##NAME: {                                                 \
+    TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
+    result += GPBCompute##NAME##Size(fieldNumber, fieldVal);                \
+    break;                                                                  \
+  }
+#define CASE_SINGLE_OBJECT(NAME)                                                \
+  case GPBDataType##NAME: {                                                     \
+    id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
+    result += GPBCompute##NAME##Size(fieldNumber, fieldVal);                    \
+    break;                                                                      \
+  }
+        CASE_SINGLE_POD(Bool, BOOL, Bool)
+        CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+        CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+        CASE_SINGLE_POD(Float, float, Float)
+        CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+        CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+        CASE_SINGLE_POD(Double, double, Double)
+        CASE_SINGLE_POD(Int32, int32_t, Int32)
+        CASE_SINGLE_POD(Int64, int64_t, Int64)
+        CASE_SINGLE_POD(SInt32, int32_t, Int32)
+        CASE_SINGLE_POD(SInt64, int64_t, Int64)
+        CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+        CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+        CASE_SINGLE_OBJECT(Bytes)
+        CASE_SINGLE_OBJECT(String)
+        CASE_SINGLE_OBJECT(Message)
+        CASE_SINGLE_OBJECT(Group)
+        CASE_SINGLE_POD(Enum, int32_t, Int32)
 #undef CASE_SINGLE_POD
 #undef CASE_SINGLE_OBJECT
       }
 
-    // Repeated Fields
+      // Repeated Fields
     } else if (fieldType == GPBFieldTypeRepeated) {
-      id genericArray =
-          GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+      id genericArray = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
       NSUInteger count = [genericArray count];
       if (count == 0) {
         continue;  // Nothing to add.
@@ -3001,41 +2942,41 @@
       __block size_t dataSize = 0;
 
       switch (fieldDataType) {
-#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE)                             \
-    CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
-#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME)  \
-        case GPBDataType##NAME: {                                             \
-          GPB##ARRAY_TYPE##Array *array = genericArray;                       \
-          [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL *stop) { \
-            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
-          }];                                                                 \
-          break;                                                              \
-        }
-#define CASE_REPEATED_OBJECT(NAME)                                            \
-        case GPBDataType##NAME: {                                             \
-          for (id value in genericArray) {                                    \
-            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
-          }                                                                   \
-          break;                                                              \
-        }
-          CASE_REPEATED_POD(Bool, BOOL, Bool)
-          CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
-          CASE_REPEATED_POD(SFixed32, int32_t, Int32)
-          CASE_REPEATED_POD(Float, float, Float)
-          CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
-          CASE_REPEATED_POD(SFixed64, int64_t, Int64)
-          CASE_REPEATED_POD(Double, double, Double)
-          CASE_REPEATED_POD(Int32, int32_t, Int32)
-          CASE_REPEATED_POD(Int64, int64_t, Int64)
-          CASE_REPEATED_POD(SInt32, int32_t, Int32)
-          CASE_REPEATED_POD(SInt64, int64_t, Int64)
-          CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
-          CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
-          CASE_REPEATED_OBJECT(Bytes)
-          CASE_REPEATED_OBJECT(String)
-          CASE_REPEATED_OBJECT(Message)
-          CASE_REPEATED_OBJECT(Group)
-          CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
+#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
+#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME)           \
+  case GPBDataType##NAME: {                                                            \
+    GPB##ARRAY_TYPE##Array *array = genericArray;                                      \
+    [array enumerate##ARRAY_ACCESSOR_NAME##                                            \
+        ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL * stop) { \
+          dataSize += GPBCompute##NAME##SizeNoTag(value);                              \
+        }];                                                                            \
+    break;                                                                             \
+  }
+#define CASE_REPEATED_OBJECT(NAME)                    \
+  case GPBDataType##NAME: {                           \
+    for (id value in genericArray) {                  \
+      dataSize += GPBCompute##NAME##SizeNoTag(value); \
+    }                                                 \
+    break;                                            \
+  }
+        CASE_REPEATED_POD(Bool, BOOL, Bool)
+        CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
+        CASE_REPEATED_POD(SFixed32, int32_t, Int32)
+        CASE_REPEATED_POD(Float, float, Float)
+        CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
+        CASE_REPEATED_POD(SFixed64, int64_t, Int64)
+        CASE_REPEATED_POD(Double, double, Double)
+        CASE_REPEATED_POD(Int32, int32_t, Int32)
+        CASE_REPEATED_POD(Int64, int64_t, Int64)
+        CASE_REPEATED_POD(SInt32, int32_t, Int32)
+        CASE_REPEATED_POD(SInt64, int64_t, Int64)
+        CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
+        CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
+        CASE_REPEATED_OBJECT(Bytes)
+        CASE_REPEATED_OBJECT(String)
+        CASE_REPEATED_OBJECT(Message)
+        CASE_REPEATED_OBJECT(Group)
+        CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
 #undef CASE_REPEATED_POD
 #undef CASE_REPEATED_POD_EXTRA
 #undef CASE_REPEATED_OBJECT
@@ -3053,20 +2994,18 @@
         result += count * tagSize;
       }
 
-    // Map<> Fields
+      // Map<> Fields
     } else {  // fieldType == GPBFieldTypeMap
       if (GPBDataTypeIsObject(fieldDataType) &&
           (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
         // If key type was string, then the map is an NSDictionary.
-        NSDictionary *map =
-            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+        NSDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
         if (map) {
           result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
         }
       } else {
         // Type will be GPB*GroupDictionary, exact type doesn't matter.
-        GPBInt32Int32Dictionary *map =
-            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+        GPBInt32Int32Dictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
         result += [map computeSerializedSizeAsField:fieldDescriptor];
       }
     }
@@ -3102,40 +3041,40 @@
                            ResolveIvarAccessorMethodResult *result) {
   GPBDataType fieldDataType = GPBGetFieldDataType(field);
   switch (fieldDataType) {
-#define CASE_GET(NAME, TYPE, TRUE_NAME)                          \
-    case GPBDataType##NAME: {                                    \
-      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
-        return GPBGetMessage##TRUE_NAME##Field(obj, field);      \
-       });                                                       \
-      result->encodingSelector = @selector(get##NAME);           \
-      break;                                                     \
-    }
-#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME)                   \
-    case GPBDataType##NAME: {                                    \
-      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
-        return GPBGetObjectIvarWithField(obj, field);            \
-       });                                                       \
-      result->encodingSelector = @selector(get##NAME);           \
-      break;                                                     \
-    }
-      CASE_GET(Bool, BOOL, Bool)
-      CASE_GET(Fixed32, uint32_t, UInt32)
-      CASE_GET(SFixed32, int32_t, Int32)
-      CASE_GET(Float, float, Float)
-      CASE_GET(Fixed64, uint64_t, UInt64)
-      CASE_GET(SFixed64, int64_t, Int64)
-      CASE_GET(Double, double, Double)
-      CASE_GET(Int32, int32_t, Int32)
-      CASE_GET(Int64, int64_t, Int64)
-      CASE_GET(SInt32, int32_t, Int32)
-      CASE_GET(SInt64, int64_t, Int64)
-      CASE_GET(UInt32, uint32_t, UInt32)
-      CASE_GET(UInt64, uint64_t, UInt64)
-      CASE_GET_OBJECT(Bytes, id, Object)
-      CASE_GET_OBJECT(String, id, Object)
-      CASE_GET_OBJECT(Message, id, Object)
-      CASE_GET_OBJECT(Group, id, Object)
-      CASE_GET(Enum, int32_t, Enum)
+#define CASE_GET(NAME, TYPE, TRUE_NAME)                        \
+  case GPBDataType##NAME: {                                    \
+    result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+      return GPBGetMessage##TRUE_NAME##Field(obj, field);      \
+    });                                                        \
+    result->encodingSelector = @selector(get##NAME);           \
+    break;                                                     \
+  }
+#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME)                 \
+  case GPBDataType##NAME: {                                    \
+    result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+      return GPBGetObjectIvarWithField(obj, field);            \
+    });                                                        \
+    result->encodingSelector = @selector(get##NAME);           \
+    break;                                                     \
+  }
+    CASE_GET(Bool, BOOL, Bool)
+    CASE_GET(Fixed32, uint32_t, UInt32)
+    CASE_GET(SFixed32, int32_t, Int32)
+    CASE_GET(Float, float, Float)
+    CASE_GET(Fixed64, uint64_t, UInt64)
+    CASE_GET(SFixed64, int64_t, Int64)
+    CASE_GET(Double, double, Double)
+    CASE_GET(Int32, int32_t, Int32)
+    CASE_GET(Int64, int64_t, Int64)
+    CASE_GET(SInt32, int32_t, Int32)
+    CASE_GET(SInt64, int64_t, Int64)
+    CASE_GET(UInt32, uint32_t, UInt32)
+    CASE_GET(UInt64, uint64_t, UInt64)
+    CASE_GET_OBJECT(Bytes, id, Object)
+    CASE_GET_OBJECT(String, id, Object)
+    CASE_GET_OBJECT(Message, id, Object)
+    CASE_GET_OBJECT(Group, id, Object)
+    CASE_GET(Enum, int32_t, Enum)
 #undef CASE_GET
   }
 }
@@ -3145,40 +3084,40 @@
                            ResolveIvarAccessorMethodResult *result) {
   GPBDataType fieldDataType = GPBGetFieldDataType(field);
   switch (fieldDataType) {
-#define CASE_SET(NAME, TYPE, TRUE_NAME)                                       \
-    case GPBDataType##NAME: {                                                 \
-      result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) {  \
-        return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value);    \
-      });                                                                     \
-      result->encodingSelector = @selector(set##NAME:);                       \
-      break;                                                                  \
-    }
-#define CASE_SET_COPY(NAME)                                                   \
-    case GPBDataType##NAME: {                                                 \
-      result->impToAdd = imp_implementationWithBlock(^(id obj, id value) {    \
-        return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
-      });                                                                     \
-      result->encodingSelector = @selector(set##NAME:);                       \
-      break;                                                                  \
-    }
-      CASE_SET(Bool, BOOL, Bool)
-      CASE_SET(Fixed32, uint32_t, UInt32)
-      CASE_SET(SFixed32, int32_t, Int32)
-      CASE_SET(Float, float, Float)
-      CASE_SET(Fixed64, uint64_t, UInt64)
-      CASE_SET(SFixed64, int64_t, Int64)
-      CASE_SET(Double, double, Double)
-      CASE_SET(Int32, int32_t, Int32)
-      CASE_SET(Int64, int64_t, Int64)
-      CASE_SET(SInt32, int32_t, Int32)
-      CASE_SET(SInt64, int64_t, Int64)
-      CASE_SET(UInt32, uint32_t, UInt32)
-      CASE_SET(UInt64, uint64_t, UInt64)
-      CASE_SET_COPY(Bytes)
-      CASE_SET_COPY(String)
-      CASE_SET(Message, id, Object)
-      CASE_SET(Group, id, Object)
-      CASE_SET(Enum, int32_t, Enum)
+#define CASE_SET(NAME, TYPE, TRUE_NAME)                                    \
+  case GPBDataType##NAME: {                                                \
+    result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
+      return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value);   \
+    });                                                                    \
+    result->encodingSelector = @selector(set##NAME:);                      \
+    break;                                                                 \
+  }
+#define CASE_SET_COPY(NAME)                                                      \
+  case GPBDataType##NAME: {                                                      \
+    result->impToAdd = imp_implementationWithBlock(^(id obj, id value) {         \
+      return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
+    });                                                                          \
+    result->encodingSelector = @selector(set##NAME:);                            \
+    break;                                                                       \
+  }
+    CASE_SET(Bool, BOOL, Bool)
+    CASE_SET(Fixed32, uint32_t, UInt32)
+    CASE_SET(SFixed32, int32_t, Int32)
+    CASE_SET(Float, float, Float)
+    CASE_SET(Fixed64, uint64_t, UInt64)
+    CASE_SET(SFixed64, int64_t, Int64)
+    CASE_SET(Double, double, Double)
+    CASE_SET(Int32, int32_t, Int32)
+    CASE_SET(Int64, int64_t, Int64)
+    CASE_SET(SInt32, int32_t, Int32)
+    CASE_SET(SInt64, int64_t, Int64)
+    CASE_SET(UInt32, uint32_t, UInt32)
+    CASE_SET(UInt64, uint64_t, UInt64)
+    CASE_SET_COPY(Bytes)
+    CASE_SET_COPY(String)
+    CASE_SET(Message, id, Object)
+    CASE_SET(Group, id, Object)
+    CASE_SET(Enum, int32_t, Enum)
 #undef CASE_SET
   }
 }
@@ -3217,8 +3156,7 @@
         result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
           if (value) {
             [NSException raise:NSInvalidArgumentException
-                        format:@"%@: %@ can only be set to NO (to clear field).",
-                               [obj class],
+                        format:@"%@: %@ can only be set to NO (to clear field).", [obj class],
                                NSStringFromSelector(field->setHasSel_)];
           }
           GPBClearMessageField(obj, field);
@@ -3262,8 +3200,7 @@
         result.impToAdd = imp_implementationWithBlock(^(id obj) {
           // Type doesn't matter, all *Array and *Dictionary types support
           // -count.
-          NSArray *arrayOrMap =
-              GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
+          NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
           return [arrayOrMap count];
         });
         result.encodingSelector = @selector(getArrayCount);
@@ -3272,8 +3209,7 @@
     }
   }
   if (result.impToAdd) {
-    const char *encoding =
-        GPBMessageEncodingForSelector(result.encodingSelector, YES);
+    const char *encoding = GPBMessageEncodingForSelector(result.encodingSelector, YES);
     Class msgClass = descriptor.messageClass;
     BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
     // class_addMethod() is documented as also failing if the method was already
@@ -3307,8 +3243,7 @@
 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
   self = [self init];
   if (self) {
-    NSData *data =
-        [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
+    NSData *data = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
     if (data.length) {
       [self mergeFromData:data extensionRegistry:nil];
     }
@@ -3355,8 +3290,7 @@
 #if defined(DEBUG) && DEBUG
   if (field.fieldType != GPBFieldTypeRepeated) {
     [NSException raise:NSInvalidArgumentException
-                format:@"%@.%@ is not a repeated field.",
-     [self class], field.name];
+                format:@"%@.%@ is not a repeated field.", [self class], field.name];
   }
 #endif
   return GetOrCreateArrayIvarWithField(self, field);
@@ -3367,8 +3301,7 @@
 #if defined(DEBUG) && DEBUG
   if (field.fieldType != GPBFieldTypeMap) {
     [NSException raise:NSInvalidArgumentException
-                format:@"%@.%@ is not a map<> field.",
-     [self class], field.name];
+                format:@"%@.%@ is not a map<> field.", [self class], field.name];
   }
 #endif
   return GetOrCreateMapIvarWithField(self, field);
diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m
index dcd4b44..1dce738 100644
--- a/objectivec/GPBUnknownFieldSet.m
+++ b/objectivec/GPBUnknownFieldSet.m
@@ -289,13 +289,6 @@
   }
 }
 
-- (void)mergeFromData:(NSData *)data {
-  GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
-  [self mergeFromCodedInputStream:input];
-  [input checkLastTagWas:0];
-  [input release];
-}
-
 - (void)mergeVarintField:(int32_t)number value:(int32_t)value {
   checkNumber(number);
   [[self mutableFieldForNumber:number create:YES] addVarint:value];
diff --git a/objectivec/GPBUnknownFieldSet_PackagePrivate.h b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
index e27127a..b65bdaa 100644
--- a/objectivec/GPBUnknownFieldSet_PackagePrivate.h
+++ b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
@@ -50,7 +50,6 @@
 - (void)mergeUnknownFields:(GPBUnknownFieldSet *)other;
 
 - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input;
-- (void)mergeFromData:(NSData *)data;
 
 - (void)mergeVarintField:(int32_t)number value:(int32_t)value;
 - (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input;
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
index 0504062..0d0d327 100644
--- a/objectivec/Tests/GPBCodedInputStreamTests.m
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -28,6 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#import <Foundation/Foundation.h>
 #import "GPBTestUtilities.h"
 
 #import "GPBCodedInputStream.h"
@@ -370,10 +371,23 @@
                                @"should throw a GPBCodedInputStreamException exception ");
 }
 
-- (void)testBytesWithNegativeSize {
-  NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F);
+- (void)testBytesOver2GB {
+  NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x02, 0x03);  // don't need all the bytes
   GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
-  XCTAssertNil([input readBytes]);
+  @try {
+    __unused NSData* result = [input readBytes];
+    XCTFail(@"Should have thrown");
+  } @catch (NSException* anException) {
+    // Ensure the correct error within the exception.
+    XCTAssertTrue([anException isKindOfClass:[NSException class]]);
+    XCTAssertEqualObjects(anException.name, GPBCodedInputStreamException);
+    NSDictionary* userInfo = anException.userInfo;
+    XCTAssertNotNil(userInfo);
+    NSError* err = userInfo[GPBCodedInputStreamUnderlyingErrorKey];
+    XCTAssertNotNil(err);
+    XCTAssertEqualObjects(err.domain, GPBCodedInputStreamErrorDomain);
+    XCTAssertEqual(err.code, GPBCodedInputStreamErrorInvalidSize);
+  }
 }
 
 // Verifies fix for b/10315336.
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index 3c2381c..5a7dc16 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -1266,12 +1266,17 @@
   XCTAssertEqual(error.code, GPBCodedInputStreamErrorRecursionDepthExceeded);
 }
 
-- (void)testParseDelimitedDataWithNegativeSize {
-  NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F");
+- (void)testParseDelimitedDataOver2GB {
+  NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F\x01\x02\0x3");  // Don't need all the bytes
   GPBCodedInputStream *input = [GPBCodedInputStream streamWithData:data];
   NSError *error;
-  [GPBMessage parseDelimitedFromCodedInputStream:input extensionRegistry:nil error:&error];
-  XCTAssertNil(error);
+  GPBMessage *result = [GPBMessage parseDelimitedFromCodedInputStream:input
+                                                    extensionRegistry:nil
+                                                                error:&error];
+  XCTAssertNil(result);
+  XCTAssertNotNil(error);
+  XCTAssertEqualObjects(error.domain, GPBCodedInputStreamErrorDomain);
+  XCTAssertEqual(error.code, GPBCodedInputStreamErrorInvalidSize);
 }
 
 #ifdef DEBUG
diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m
index b98f52e..dbb6eb4 100644
--- a/objectivec/Tests/GPBUnknownFieldSetTest.m
+++ b/objectivec/Tests/GPBUnknownFieldSetTest.m
@@ -381,7 +381,8 @@
   NSData* data = [fields data];
 
   GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease];
-  [parsed mergeFromData:data];
+  GPBCodedInputStream* input = [[[GPBCodedInputStream alloc] initWithData:data] autorelease];
+  [parsed mergeFromCodedInputStream:input];
   GPBUnknownField* field2 = [parsed getField:1];
   XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
   XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]);
diff --git a/objectivec/defs.bzl b/objectivec/defs.bzl
new file mode 100644
index 0000000..5535868
--- /dev/null
+++ b/objectivec/defs.bzl
@@ -0,0 +1,68 @@
+"""Starlark helpers for Objective-C protos."""
+
+# State constants for objc_proto_camel_case_name.
+_last_was_other = 0
+_last_was_lowercase = 1
+_last_was_uppercase = 2
+_last_was_number = 3
+
+def objc_proto_camel_case_name(name):
+    """A Starlark version of the ObjC generator's CamelCase name transform.
+
+    This needs to track
+    src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase()
+
+    NOTE: This code is written to model the C++ in protoc's ObjC generator so it
+    is easier to confirm that the algorithms between the implementations match.
+    The customizations for starlark performance are:
+    - The cascade within the loop is reordered and special cases "_" to
+      optimize for google3 inputs.
+    - The "last was" state is handled via integers instead of three booleans.
+
+    The `first_capitalized` argument in the C++ code is left off this code and
+    it acts as if the value were `True`.
+
+    Args:
+      name: The proto file name to convert to camel case. The extension should
+        already be removed.
+
+    Returns:
+      The converted proto name to camel case.
+    """
+    segments = []
+    current = ""
+    last_was = _last_was_other
+    for c in name.elems():
+        if c.islower():
+            # lowercase letter can follow a lowercase or uppercase letter.
+            if last_was != _last_was_lowercase and last_was != _last_was_uppercase:
+                segments.append(current)
+                current = c.upper()
+            else:
+                current += c
+            last_was = _last_was_lowercase
+        elif c == "_":  # more common than rest, special case it.
+            last_was = _last_was_other
+        elif c.isdigit():
+            if last_was != _last_was_number:
+                segments.append(current)
+                current = ""
+            current += c
+            last_was = _last_was_number
+        elif c.isupper():
+            if last_was != _last_was_uppercase:
+                segments.append(current)
+                current = c
+            else:
+                current += c.lower()
+            last_was = _last_was_uppercase
+        else:
+            last_was = _last_was_other
+    segments.append(current)
+    result = ""
+    for x in segments:
+        if x in ("Url", "Http", "Https"):
+            result += x.upper()
+        else:
+            result += x
+    return result
diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh
index 7e23a99..4b77412 100755
--- a/objectivec/generate_well_known_types.sh
+++ b/objectivec/generate_well_known_types.sh
@@ -9,8 +9,7 @@
 readonly ObjCDir="${ScriptDir}"
 readonly ProtoRootDir="${ObjCDir}/.."
 
-# Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+cd "${ProtoRootDir}"
 
 # Flag for continuous integration to check that everything is current.
 CHECK_ONLY=0
@@ -19,7 +18,11 @@
   shift
 fi
 
-cd "${ProtoRootDir}"
+readonly PROTOC_PATH="${PROTOC:-${ProtoRootDir}/bazel-bin/protoc}"
+if [[ ! -x "${PROTOC_PATH}" ]] ; then
+  echo "Failed to find executable protoc: ${PROTOC_PATH}"
+  exit 1
+fi
 
 if [[ ! -e src/google/protobuf/stubs/common.h ]]; then
   cat >&2 << __EOF__
@@ -29,9 +32,6 @@
   exit 1
 fi
 
-# Make sure the compiler is current.
-${BazelBin} build //:protoc $@
-
 cd src
 declare -a RUNTIME_PROTO_FILES=( \
   google/protobuf/any.proto \
@@ -50,7 +50,7 @@
 # Generate to a temp directory to see if they match.
 TMP_DIR=$(mktemp -d)
 trap "rm -rf ${TMP_DIR}" EXIT
-${ProtoRootDir}/bazel-bin/protoc --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
+"${PROTOC_PATH}" --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
 
 DID_COPY=0
 for PROTO_FILE in "${RUNTIME_PROTO_FILES[@]}"; do
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index 72c7809..09daffa 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -406,13 +406,13 @@
     return;
   }
 
-  if (size == 0 || index != size - 1) {
+  if (size == 0 || index < 0 || index >= size) {
     php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n",
                      index);
     return;
   }
 
-  upb_Array_Resize(intern->array, size - 1, Arena_Get(&intern->arena));
+  upb_Array_Delete(intern->array, index, 1);
 }
 
 /**
diff --git a/php/src/Google/Protobuf/Internal/RepeatedField.php b/php/src/Google/Protobuf/Internal/RepeatedField.php
index ea7971f..f6ecd1c 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedField.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedField.php
@@ -219,13 +219,13 @@
     public function offsetUnset($offset)
     {
         $count = count($this->container);
-        if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) {
+        if (!is_numeric($offset) || $count === 0 || $offset < 0 || $offset >= $count) {
             trigger_error(
                 "Cannot remove element at the given index",
                 E_USER_ERROR);
             return;
         }
-        array_pop($this->container);
+        array_splice($this->container, $offset, 1);
     }
 
     /**
diff --git a/php/tests/ArrayTest.php b/php/tests/ArrayTest.php
index 9e8fcb8..2cade79 100644
--- a/php/tests/ArrayTest.php
+++ b/php/tests/ArrayTest.php
@@ -655,4 +655,31 @@
         $arr2 = clone $arr;
         $this->assertSame($arr[0], $arr2[0]);
     }
+
+    #########################################################
+    # Test offsetUnset
+    #########################################################
+
+    public function testOffsetUnset()
+    {
+        $arr = new RepeatedField(GPBType::INT32);
+        $arr[] = 0;
+        $arr[] = 1;
+        $arr[] = 2;
+
+        $this->assertSame(3, count($arr));
+        $this->assertSame(0, $arr[0]);
+        $this->assertSame(1, $arr[1]);
+        $this->assertSame(2, $arr[2]);
+
+        $arr->offsetUnset(1);
+        $this->assertSame(0, $arr[0]);
+        $this->assertSame(2, $arr[1]);
+
+        $arr->offsetUnset(0);
+        $this->assertSame(2, $arr[0]);
+
+        $arr->offsetUnset(0);
+        $this->assertCount(0, $arr);
+    }
 }
diff --git a/push_auto_update.sh b/push_auto_update.sh
index 0d0e437..9972da6 100755
--- a/push_auto_update.sh
+++ b/push_auto_update.sh
@@ -39,6 +39,7 @@
   commit_message="Auto-generate files"
 fi
 
+git pull --rebase
 git add -A
 git diff --staged --quiet || git commit -am "$commit_message"
 git push
diff --git a/regenerate_stale_files.sh b/regenerate_stale_files.sh
index 1c38104..58c640b 100755
--- a/regenerate_stale_files.sh
+++ b/regenerate_stale_files.sh
@@ -15,6 +15,7 @@
 # Run and fix all staleness tests.
 ${BazelBin} test src:cmake_lists_staleness_test "$@" || ./bazel-bin/src/cmake_lists_staleness_test --fix
 ${BazelBin} test src/google/protobuf:well_known_types_staleness_test "$@" || ./bazel-bin/src/google/protobuf/well_known_types_staleness_test --fix
+${BazelBin} test objectivec:well_known_types_staleness_test "$@" || ./bazel-bin/objectivec/well_known_types_staleness_test --fix
 
 # Generate C# code.
 # This doesn't currently have Bazel staleness tests, but there's an existing
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel
index d986479..e3db90c 100644
--- a/src/google/protobuf/BUILD.bazel
+++ b/src/google/protobuf/BUILD.bazel
@@ -1257,6 +1257,7 @@
         "//src/google/protobuf/io",
         "//src/google/protobuf/stubs",
         "//src/google/protobuf/testing",
+        "@com_google_absl//absl/functional:bind_front",
         "@com_google_absl//absl/synchronization",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index e9e7a15..23e6999 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -681,11 +681,6 @@
   friend struct internal::ArenaTestPeer;
 };
 
-template <>
-inline void* Arena::AllocateInternal<std::string, false>() {
-  return impl_.AllocateFromStringBlock();
-}
-
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
index 9744204..19bd6b5 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
@@ -51,6 +51,7 @@
 namespace compiler {
 namespace cpp {
 namespace {
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
 using Sub = ::google::protobuf::io::Printer::Sub;
 
 std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) {
@@ -172,7 +173,8 @@
 
 void SingularEnum::GenerateAccessorDeclarations(io::Printer* p) const {
   auto v = p->WithVars(
-      AnnotatedAccessors(field_, {"", "set_", "_internal_", "_internal_set_"}));
+      AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+  auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
   p->Emit(R"cc(
     $DEPRECATED$ $Enum$ $name$() const;
     $DEPRECATED$ void $set_name$($Enum$ value);
@@ -331,9 +333,12 @@
 };
 
 void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
-  auto v = p->WithVars(
-      AnnotatedAccessors(field_, {"", "set_", "add_", "mutable_", "_internal_",
-                                  "_internal_add_", "_internal_mutable_"}));
+  auto v = p->WithVars(AnnotatedAccessors(
+      field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+  auto vs =
+      p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+  auto vm =
+      p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
 
   p->Emit(R"cc(
     public:
diff --git a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
index 79f1015..a91a394 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
@@ -30,6 +30,7 @@
 
 #include <memory>
 #include <string>
+#include <tuple>
 
 #include "absl/container/flat_hash_map.h"
 #include "absl/log/absl_check.h"
@@ -141,10 +142,12 @@
       "    ${1$_internal_mutable_$name$$}$();\n"
       "public:\n"
       "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
-      "    ${1$$name$$}$() const;\n"
+      "    ${1$$name$$}$() const;\n",
+      descriptor_);
+  format(
       "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
       "    ${1$mutable_$name$$}$();\n",
-      descriptor_);
+      std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS));
 }
 
 void MapFieldGenerator::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
index 6eaadef..b4bf2a9 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
@@ -809,9 +809,11 @@
       "$type$* ${1$_internal_add_$name$$}$();\n"
       "public:\n",
       descriptor_);
+  format("$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n",
+         descriptor_);
+  format("$deprecated_attr$$type$* ${1$add_$name$$}$();\n",
+         std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
   format(
-      "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
-      "$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
       "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
       "    ${1$$name$$}$() const;\n",
       descriptor_);
diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
index 5bbf298..b15801e 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
@@ -56,7 +56,7 @@
 using ::google::protobuf::internal::WireFormat;
 using ::google::protobuf::internal::WireFormatLite;
 using Sub = ::google::protobuf::io::Printer::Sub;
-using Annotation = ::google::protobuf::GeneratedCodeInfo::Annotation;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
 
 // For encodings with fixed sizes, returns that size in bytes.
 absl::optional<size_t> FixedSize(FieldDescriptor::Type type) {
@@ -193,18 +193,10 @@
 };
 
 void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
+  auto v = p->WithVars(
+      AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+  auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
   p->Emit(
-      {
-          Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
-          Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("_internal_name",
-              absl::StrCat("_internal_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("_internal_set_name",
-              absl::StrCat("_internal_set_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-      },
       R"cc(
         $DEPRECATED$ $Type$ $name$() const;
         $DEPRECATED$ void $set_name$($Type$ value);
@@ -397,41 +389,27 @@
 }
 
 void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
-  p->Emit(
-      {
-          Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
-          Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("add_name", absl::StrCat("add_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("mutable_name", absl::StrCat("mutable_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
+  auto v = p->WithVars(AnnotatedAccessors(
+      field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+  auto vs =
+      p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+  auto va =
+      p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
+  p->Emit(R"cc(
+    $DEPRECATED$ $Type$ $name$(int index) const;
+    $DEPRECATED$ void $set_name$(int index, $Type$ value);
+    $DEPRECATED$ void $add_name$($Type$ value);
+    $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
+    $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
 
-          Sub("_internal_name",
-              absl::StrCat("_internal_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("_internal_add_name",
-              absl::StrCat("_internal_add_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-          Sub("_internal_mutable_name",
-              absl::StrCat("_internal_mutable_", p->LookupVar("name")))
-              .AnnotatedAs(field_),
-      },
-      R"cc(
-        $DEPRECATED$ $Type$ $name$(int index) const;
-        $DEPRECATED$ void $set_name$(int index, $Type$ value);
-        $DEPRECATED$ void $add_name$($Type$ value);
-        $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
-        $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
+    private:
+    $Type$ $_internal_name$(int index) const;
+    void $_internal_add_name$($Type$ value);
+    const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
+    $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
 
-        private:
-        $Type$ $_internal_name$(int index) const;
-        void $_internal_add_name$($Type$ value);
-        const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
-        $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
-
-        public:
-      )cc");
+    public:
+  )cc");
 }
 
 void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index e815e8b..7b14149 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -211,9 +211,9 @@
 
 // Returns true if "field" is a message field that is backed by LazyField per
 // profile (go/pdlazy).
-inline bool IsEagerlyVerifiedLazyByProfile(const FieldDescriptor* field,
-                                           const Options& options,
-                                           MessageSCCAnalyzer* scc_analyzer) {
+inline bool IsLazyByProfile(const FieldDescriptor* field,
+                            const Options& options,
+                            MessageSCCAnalyzer* scc_analyzer) {
   return false;
 }
 
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 88bb015..a9cb054 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -85,6 +85,7 @@
 using ::google::protobuf::internal::WireFormatLite;
 using ::google::protobuf::internal::cpp::HasHasbit;
 using ::google::protobuf::internal::cpp::Utf8CheckMode;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
 using Sub = ::google::protobuf::io::Printer::Sub;
 
 static constexpr int kNoHasbit = -1;
@@ -730,7 +731,10 @@
          {"clearer",
           [&] {
             p->Emit({Sub("clear_name", absl::StrCat("clear_", name))
-                         .AnnotatedAs(field)},
+                         .AnnotatedAs({
+                             field,
+                             Semantic::kSet,
+                         })},
                     R"cc(
                       $deprecated_attr $void $clear_name$() $impl$;
                     )cc");
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index feb5a7f..e95ee56 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -177,6 +177,270 @@
   EXPECT_FALSE(atu::GetAnnotationSubstring(test, annotation).has_value());
 }
 
+constexpr absl::string_view kEnumFieldTestFile = R"(
+  syntax = "proto2";
+  package foo;
+  enum Enum { VALUE = 0; }
+  message Message {
+    optional Enum efield = 1;
+    repeated Enum refield = 2;
+  }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesEnumSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kEnumFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                              DescriptorProto::kFieldFieldNumber, 0};
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "efield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_efield" || *substring == "clear_efield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    }
+  }
+  field_path.back() = 1;
+  annotations.clear();
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "refield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_refield" || *substring == "clear_refield" ||
+               *substring == "add_refield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_refield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+}
+
+constexpr absl::string_view kMapFieldTestFile = R"(
+  syntax = "proto2";
+  package foo;
+  message Message {
+    map<string, int32> mfield = 1;
+  }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesMapSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kMapFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                              DescriptorProto::kFieldFieldNumber, 0};
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "clear_mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+}
+
+constexpr absl::string_view kPrimFieldTestFile = R"(
+  syntax = "proto2";
+  package foo;
+  message Message {
+    optional int32 ifield = 1;
+    repeated int32 rifield = 2;
+  }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesPrimSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kPrimFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                              DescriptorProto::kFieldFieldNumber, 0};
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "ifield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_ifield" || *substring == "clear_ifield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    }
+  }
+  field_path.back() = 1;
+  annotations.clear();
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "rifield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_rifield" || *substring == "clear_rifield" ||
+               *substring == "add_rifield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_rifield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+}
+
+constexpr absl::string_view kCordFieldTestFile = R"(
+    syntax = "proto2";
+    package foo;
+    message Message {
+      optional string sfield = 1 [ctype = CORD];
+      repeated string rsfield = 2 [ctype = CORD];
+    }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesCordSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kCordFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                              DescriptorProto::kFieldFieldNumber, 0};
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+  field_path.back() = 1;
+  annotations.clear();
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+               *substring == "add_rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+}
+
+constexpr absl::string_view kStringPieceFieldTestFile = R"(
+    syntax = "proto2";
+    package foo;
+    message Message {
+      optional string sfield = 1 [ctype = STRING_PIECE];
+      repeated string rsfield = 2 [ctype = STRING_PIECE];
+    }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesStringPieceSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kStringPieceFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                              DescriptorProto::kFieldFieldNumber, 0};
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_sfield" || *substring == "set_alias_sfield" ||
+               *substring == "clear_sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_sfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+  field_path.back() = 1;
+  annotations.clear();
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "set_rsfield" ||
+               *substring == "set_alias_rsfield" ||
+               *substring == "clear_rsfield" ||
+               *substring == "add_alias_rsfield" ||
+               *substring == "add_rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_rsfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    }
+  }
+}
+
 constexpr absl::string_view kStringFieldTestFile = R"(
     syntax = "proto2";
     package foo;
@@ -205,7 +469,7 @@
     if (*substring == "sfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
                 annotation->semantic());
-    } else if (*substring == "set_sfield") {
+    } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
                 annotation->semantic());
     } else if (*substring == "mutable_sfield") {
@@ -223,7 +487,8 @@
     if (*substring == "rsfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
                 annotation->semantic());
-    } else if (*substring == "set_rsfield") {
+    } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+               *substring == "add_rsfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
                 annotation->semantic());
     } else if (*substring == "mutable_rsfield") {
@@ -265,6 +530,9 @@
     if (*substring == "mfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
                 annotation->semantic());
+    } else if (*substring == "clear_mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
     } else if (*substring == "mutable_mfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
                 annotation->semantic());
@@ -277,15 +545,60 @@
   for (const auto* annotation : annotations) {
     auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
     ASSERT_TRUE(substring.has_value());
-    if (substring == "rmfield") {
+    if (*substring == "rmfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
                 annotation->semantic());
-    } else if (substring == "mutable_rmfield") {
+    } else if (*substring == "add_rmfield" || *substring == "clear_rmfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    } else if (*substring == "mutable_rmfield") {
       EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
                 annotation->semantic());
     }
   }
 }
+
+constexpr absl::string_view kLazyMessageFieldTestFile = R"(
+    syntax = "proto2";
+    package foo;
+    message SMessage { }
+    message Message {
+      optional SMessage mfield = 1 [lazy=true];
+    }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesLazyMessageSemantics) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kLazyMessageFieldTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(1).name());
+  std::vector<int> field_path;
+  field_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+  field_path.push_back(1);
+  field_path.push_back(DescriptorProto::kFieldFieldNumber);
+  field_path.push_back(0);
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+  EXPECT_TRUE(!annotations.empty());
+  for (const auto* annotation : annotations) {
+    auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+    ASSERT_TRUE(substring.has_value());
+    if (*substring == "mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+                annotation->semantic());
+    } else if (*substring == "mutable_mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+                annotation->semantic());
+    } else if (*substring == "set_encoded_mfield" ||
+               *substring == "clear_mfield") {
+      EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+                annotation->semantic());
+    }
+  }
+}
 }  // namespace
 }  // namespace cpp
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
index 7e93fcd..791a7d5 100644
--- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
@@ -494,14 +494,10 @@
       } else {
         format("0,  // no _has_bits_\n");
       }
-      if (descriptor_->extension_range_count() == 1) {
-        format(
-            "PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n"
-            "$1$, $2$,  // extension_range_{low,high}\n",
-            descriptor_->extension_range(0)->start,
-            descriptor_->extension_range(0)->end);
+      if (descriptor_->extension_range_count() != 0) {
+        format("PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n");
       } else {
-        format("0, 0, 0,  // no _extensions_\n");
+        format("0, // no _extensions_\n");
       }
       format("$1$, $2$,  // max_field_number, fast_idx_mask\n",
              (ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()),
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 9e3a49d..efcd86e 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -5375,6 +5375,7 @@
 
 }  // namespace
 
+
 void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
                                      const Descriptor* parent,
                                      Descriptor* result,
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index f6359e8..22bc03c 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -65,6 +65,7 @@
 #include "google/protobuf/port.h"
 #include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
+#include "absl/container/btree_map.h"
 #include "absl/container/flat_hash_map.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
@@ -1902,7 +1903,7 @@
     // in a .proto file.
     enum ErrorLocation {
       NAME,           // the symbol name, or the package name for files
-      NUMBER,         // field or extension range number
+      NUMBER,         // field, extension range or extension decl number
       TYPE,           // field type
       EXTENDEE,       // field extendee
       DEFAULT_VALUE,  // field default value
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 80eebfe..64e6b2c 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -3979,6 +3979,16 @@
     BuildFileInTestPool(DescriptorProto::descriptor()->file());
   }
 
+  void BuildDescriptorMessagesInTestPoolWithErrors(
+      absl::string_view expected_errors) {
+    FileDescriptorProto file_proto;
+    DescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+    MockErrorCollector error_collector;
+    EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
+                nullptr);
+    EXPECT_EQ(error_collector.text_, expected_errors);
+  }
+
   DescriptorPool pool_;
 };
 
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 80a3eb5..efe5d7a 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -3092,9 +3092,9 @@
   // We use `operator new` here because the destruction will be done with
   // `operator delete` unconditionally.
   void* p = ::operator new(sizeof(Table));
-  auto* full_table = ::new (p) Table{
-      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
-      {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
+  auto* full_table = ::new (p)
+      Table{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
+            {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
   ABSL_DCHECK_EQ(static_cast<void*>(&full_table->header),
                  static_cast<void*>(full_table));
   return &full_table->header;
@@ -3292,14 +3292,19 @@
   void* p = ::operator new(byte_size);
   auto* res = ::new (p) TcParseTableBase{
       static_cast<uint16_t>(schema_.HasHasbits() ? schema_.HasBitsOffset() : 0),
-      // extensions handled through reflection.
-      0, 0, 0,
+      schema_.HasExtensionSet()
+          ? static_cast<uint16_t>(schema_.GetExtensionSetOffset())
+          : uint16_t{0},
       static_cast<uint32_t>(fields.empty() ? 0 : fields.back()->number()),
-      static_cast<uint8_t>((fast_entries_count - 1) << 3), lookup_table_offset,
-      table_info.num_to_entry_table.skipmap32, field_entry_offset,
+      static_cast<uint8_t>((fast_entries_count - 1) << 3),
+      lookup_table_offset,
+      table_info.num_to_entry_table.skipmap32,
+      field_entry_offset,
       static_cast<uint16_t>(fields.size()),
-      static_cast<uint16_t>(table_info.aux_entries.size()), aux_offset,
-      schema_.default_instance_, &internal::TcParser::ReflectionFallback};
+      static_cast<uint16_t>(table_info.aux_entries.size()),
+      aux_offset,
+      schema_.default_instance_,
+      &internal::TcParser::ReflectionFallback};
 
   // Now copy the rest of the payloads
   PopulateTcParseFastEntries(table_info, res->fast_entry(0));
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
index dd4845b..33b094e 100644
--- a/src/google/protobuf/generated_message_tctable_decl.h
+++ b/src/google/protobuf/generated_message_tctable_decl.h
@@ -54,6 +54,7 @@
 // Additional information about this field:
 struct TcFieldData {
   constexpr TcFieldData() : data(0) {}
+  explicit constexpr TcFieldData(uint64_t data) : data(data) {}
 
   // Fast table entry constructor:
   constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
@@ -63,6 +64,24 @@
              uint64_t{hasbit_idx} << 16 |  //
              uint64_t{coded_tag}) {}
 
+  // Constructor to create an explicit 'uninitialized' instance.
+  // This constructor can be used to pass an uninitialized `data` value to a
+  // table driven parser function that does not use `data`. The purpose of this
+  // is that it allows the compiler to reallocate and re-purpose the register
+  // that is currently holding its value for other data. This reduces register
+  // allocations inside the highly optimized varint parsing functions.
+  //
+  // Applications not using `data` use the `PROTOBUF_TC_PARAM_NO_DATA_DECL`
+  // macro to declare the standard input arguments with no name for the `data`
+  // argument. Callers then use the `PROTOBUF_TC_PARAM_NO_DATA_PASS` macro.
+  //
+  // Example:
+  //   if (ptr == nullptr) {
+  //      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  //   }
+  struct DefaultInit {};
+  TcFieldData(DefaultInit) {}  // NOLINT(google-explicit-constructor)
+
   // Fields used in fast table parsing:
   //
   //     Bit:
@@ -122,7 +141,9 @@
   uint32_t tag() const { return static_cast<uint32_t>(data); }
   uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
 
-  uint64_t data;
+  union {
+    uint64_t data;
+  };
 };
 
 struct TcParseTableBase;
@@ -149,8 +170,6 @@
   // Common attributes for message layout:
   uint16_t has_bits_offset;
   uint16_t extension_offset;
-  uint32_t extension_range_low;
-  uint32_t extension_range_high;
   uint32_t max_field_number;
   uint8_t fast_idx_mask;
   uint16_t lookup_table_offset;
@@ -173,7 +192,6 @@
   // compiled.
   constexpr TcParseTableBase(
       uint16_t has_bits_offset, uint16_t extension_offset,
-      uint32_t extension_range_low, uint32_t extension_range_high,
       uint32_t max_field_number, uint8_t fast_idx_mask,
       uint16_t lookup_table_offset, uint32_t skipmap32,
       uint32_t field_entries_offset, uint16_t num_field_entries,
@@ -181,8 +199,6 @@
       const MessageLite* default_instance, TailCallParseFunc fallback)
       : has_bits_offset(has_bits_offset),
         extension_offset(extension_offset),
-        extension_range_low(extension_range_low),
-        extension_range_high(extension_range_high),
         max_field_number(max_field_number),
         fast_idx_mask(fast_idx_mask),
         lookup_table_offset(lookup_table_offset),
diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc
index b829bb7..a5791f9 100644
--- a/src/google/protobuf/generated_message_tctable_gen.cc
+++ b/src/google/protobuf/generated_message_tctable_gen.cc
@@ -824,8 +824,7 @@
   // If there are no fallback fields, and at most one extension range, the
   // parser can use a generic fallback function. Otherwise, a message-specific
   // fallback routine is needed.
-  use_generated_fallback =
-      !fallback_fields.empty() || descriptor->extension_range_count() > 1;
+  use_generated_fallback = !fallback_fields.empty();
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index a39245d..1adea2d 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -292,7 +292,7 @@
   //    the function is used as a way to get a UnknownFieldOps vtable, returned
   //    via the `const char*` return type. See `GetUnknownFieldOps()`
 
-  static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_DECL) {
+  static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_NO_DATA_DECL) {
     return ptr == nullptr;
   }
 
@@ -359,36 +359,16 @@
   static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
   static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
 
-  // Manually unrolled and specialized Varint parsing.
-  template <typename FieldType, int data_offset, int hasbit_idx>
-  static const char* FastTV32S1(PROTOBUF_TC_PARAM_DECL);
-  template <typename FieldType, int data_offset, int hasbit_idx>
-  static const char* FastTV64S1(PROTOBUF_TC_PARAM_DECL);
-  template <int data_offset, int hasbit_idx>
-  static const char* FastTV8S1(PROTOBUF_TC_PARAM_DECL);
-
-  template <typename FieldType, int data_offset, int hasbit_idx>
+  template <typename FieldType, int unused_data_offset, int unused_hasbit_idx>
   static constexpr TailCallParseFunc SingularVarintNoZag1() {
     if (sizeof(FieldType) == 1) {
-      if (data_offset < 100) {
-        return &FastTV8S1<data_offset, hasbit_idx>;
-      } else {
-        return &FastV8S1;
-      }
+      return &FastV8S1;
     }
     if (sizeof(FieldType) == 4) {
-      if (data_offset < 100) {
-        return &FastTV32S1<FieldType, data_offset, hasbit_idx>;
-      } else {  //
-        return &FastV32S1;
-      }
+      return &FastV32S1;
     }
     if (sizeof(FieldType) == 8) {
-      if (data_offset < 128) {
-        return &FastTV64S1<FieldType, data_offset, hasbit_idx>;
-      } else {
-        return &FastV64S1;
-      }
+      return &FastV64S1;
     }
     static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
                       sizeof(FieldType) == 8,
@@ -529,12 +509,16 @@
   // NOTE: Currently, this function only calls the table-level fallback
   // function, so it should only be called as the fallback from fast table
   // parsing.
-  static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+  static const char* MiniParse(PROTOBUF_TC_PARAM_NO_DATA_DECL);
 
   static const char* FastEndG1(PROTOBUF_TC_PARAM_DECL);
   static const char* FastEndG2(PROTOBUF_TC_PARAM_DECL);
 
  private:
+  // Optimized small tag varint parser for int32/int64
+  template <typename FieldType>
+  static const char* FastVarintS1(PROTOBUF_TC_PARAM_DECL);
+
   friend class GeneratedTcTableLiteTest;
   static void* MaybeGetSplitBase(MessageLite* msg, const bool is_split,
                                  const TcParseTableBase* table);
@@ -569,10 +553,10 @@
     }
   }
 
-  static const char* TagDispatch(PROTOBUF_TC_PARAM_DECL);
-  static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL);
-  static const char* ToParseLoop(PROTOBUF_TC_PARAM_DECL);
-  static const char* Error(PROTOBUF_TC_PARAM_DECL);
+  static const char* TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+  static const char* ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+  static const char* ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+  static const char* Error(PROTOBUF_TC_PARAM_NO_DATA_DECL);
 
   static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
 
@@ -618,18 +602,21 @@
       return ptr;
     }
 
-    uint32_t num = tag >> 3;
-    if (table->extension_range_low <= num &&
-        num <= table->extension_range_high) {
+    if (table->extension_offset != 0) {
+      // We don't need to check the extension ranges. If it is not an extension
+      // it will be handled just like if it was an unknown extension: sent to
+      // the unknown field set.
       return RefAt<ExtensionSet>(msg, table->extension_offset)
           .ParseField(tag, ptr,
                       static_cast<const MessageBaseT*>(table->default_instance),
                       &msg->_internal_metadata_, ctx);
+    } else {
+      // Otherwise, we directly put it on the unknown field set.
+      return UnknownFieldParse(
+          tag,
+          msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
+          ptr, ctx);
     }
-
-    return UnknownFieldParse(
-        tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
-        ptr, ctx);
   }
 
   // Note: `inline` is needed on template function declarations below to avoid
@@ -726,262 +713,14 @@
   static const char* MpFallback(PROTOBUF_TC_PARAM_DECL);
 };
 
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
-                                                                uint64_t ones) {
-  return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
-}
-
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
-// put the new value in res.  Return whether the result was negative.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
-    uint64_t byte, uint64_t ones, int64_t& res) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
-  // For the first two rounds (ptr[1] and ptr[2]), micro benchmarks show a
-  // substantial improvement from capturing the sign from the condition code
-  // register on x86-64.
-  bool sign_bit;
-  asm("shldq %3, %2, %1"
-      : "=@ccs"(sign_bit), "+r"(byte)
-      : "r"(ones), "i"(n * 7));
-  res = static_cast<int64_t>(byte);
-  return sign_bit;
-#else
-  // Generic fallback:
-  res = shift_left_fill_with_ones<n>(byte, ones);
-  return res < 0;
-#endif
-}
-
-template <class VarintType>
-inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
-ParseFallbackPair(const char* p, int64_t res1) {
-  constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
-  constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
-  static_assert(kIs64BitVarint || kIs32BitVarint,
-                "Only 32 or 64 bit varints are supported");
-  auto ptr = reinterpret_cast<const int8_t*>(p);
-
-  // The algorithm relies on sign extension for each byte to set all high bits
-  // when the varint continues. It also relies on asserting all of the lower
-  // bits for each successive byte read. This allows the result to be aggregated
-  // using a bitwise AND. For example:
-  //
-  //          8       1          64     57 ... 24     17  16      9  8       1
-  // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111  1111 1111  1aaa aaaa
-  // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111  11bb bbbb  b111 1111
-  // ptr[2] = 1ccc cccc ; res3 = 0000 0000 ... 000c cccc  cc11 1111  1111 1111
-  //                             ---------------------------------------------
-  //        res1 & res2 & res3 = 0000 0000 ... 000c cccc  ccbb bbbb  baaa aaaa
-  //
-  // On x86-64, a shld from a single register filled with enough 1s in the high
-  // bits can accomplish all this in one instruction. It so happens that res1
-  // has 57 high bits of ones, which is enough for the largest shift done.
-  //
-  // Just as importantly, by keeping results in res1, res2, and res3, we take
-  // advantage of the superscalar abilities of the CPU.
-  ABSL_DCHECK_EQ(res1 >> 7, -1);
-  uint64_t ones = res1;  // save the high 1 bits from res1 (input to SHLD)
-  int64_t res2, res3;    // accumulated result chunks
-
-  if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
-    goto done2;
-  if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
-    goto done3;
-
-  // For the remainder of the chunks, check the sign of the AND result.
-  res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
-  if (res2 >= 0) goto done4;
-  res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
-  if (res1 >= 0) goto done5;
-  if (kIs64BitVarint) {
-    res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
-    if (res2 >= 0) goto done6;
-    res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
-    if (res3 >= 0) goto done7;
-    res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
-    if (res1 >= 0) goto done8;
-    res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
-    if (res3 >= 0) goto done9;
-  } else if (kIs32BitVarint) {
-    if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
-    if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
-    if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
-    if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
-  }
-
-  // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
-  // case, the continuation bit of ptr[8] already set the top bit of res3
-  // correctly, so all we have to do is check that the expected case is true.
-  if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
-
-  if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
-    // If the continue bit is set, it is an unterminated varint.
-    return {nullptr, 0};
-  }
-
-  // A zero value of the first bit of the 10th byte represents an
-  // over-serialized varint. This case should not happen, but if does (say, due
-  // to a nonconforming serializer), deassert the continuation bit that came
-  // from ptr[8].
-  if (kIs64BitVarint && (ptr[9] & 1) == 0) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
-    // Use a small instruction since this is an uncommon code path.
-    asm("btcq $63,%0" : "+r"(res3));
-#else
-    res3 ^= static_cast<uint64_t>(1) << 63;
-#endif
-  }
-  goto done10;
-
-done2:
-  return {p + 2, res1 & res2};
-done3:
-  return {p + 3, res1 & res2 & res3};
-done4:
-  return {p + 4, res1 & res2 & res3};
-done5:
-  return {p + 5, res1 & res2 & res3};
-done6:
-  return {p + 6, res1 & res2 & res3};
-done7:
-  return {p + 7, res1 & res2 & res3};
-done8:
-  return {p + 8, res1 & res2 & res3};
-done9:
-  return {p + 9, res1 & res2 & res3};
-done10:
-  return {p + 10, res1 & res2 & res3};
-}
-
-// Notes:
-// 1) if data_offset is negative, it's read from data.offset()
-// 2) if hasbit_idx is negative, it's read from data.hasbit_idx()
-template <int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV8S1(PROTOBUF_TC_PARAM_DECL) {
-  using TagType = uint8_t;
-
-  // Special case for a varint bool field with a tag of 1 byte:
-  // The coded_tag() field will actually contain the value too and we can check
-  // both at the same time.
-  auto coded_tag = data.coded_tag<uint16_t>();
-  if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
-    auto& field =
-        RefAt<bool>(msg, data_offset >= 0 ? data_offset : data.offset());
-    // Note: we use `data.data` because Clang generates suboptimal code when
-    // using coded_tag.
-    // In x86_64 this uses the CH register to read the second byte out of
-    // `data`.
-    uint8_t value = data.data >> 8;
-    // The assume allows using a mov instead of test+setne.
-    PROTOBUF_ASSUME(value <= 1);
-    field = static_cast<bool>(value);
-
-    ptr += sizeof(TagType) + 1;  // Consume the tag and the value.
-    if (hasbit_idx < 0) {
-      hasbits |= (uint64_t{1} << data.hasbit_idx());
-    } else {
-      if (hasbit_idx < 32) {
-        // `& 31` avoids a compiler warning when hasbit_idx is negative.
-        hasbits |= (uint64_t{1} << (hasbit_idx & 31));
-      } else {
-        static_assert(hasbit_idx == 63 || (hasbit_idx < 32),
-                      "hard-coded hasbit_idx should be 0-31, or the special"
-                      "value 63, which indicates the field has no has-bit.");
-        // TODO(jorg): investigate whether higher hasbit indices are worth
-        // supporting. Something like:
-        // auto& hasblock = TcParser::RefAt<uint32_t>(msg, hasbit_idx / 32 * 4);
-        // hasblock |= uint32_t{1} << (hasbit_idx % 32);
-      }
-    }
-
-    PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-  }
-
-  // If it didn't match above either the tag is wrong, or the value is encoded
-  // non-canonically.
-  // Jump to MiniParse as wrong tag is the most probable reason.
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV64S1(PROTOBUF_TC_PARAM_DECL) {
-  using TagType = uint8_t;
-  // super-early success test...
-  if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
-    ptr += sizeof(TagType);  // Consume tag
-    if (hasbit_idx < 32) {
-      hasbits |= (uint64_t{1} << hasbit_idx);
-    }
-    uint8_t value = data.data >> 8;
-    RefAt<FieldType>(msg, data_offset) = value;
-    ptr += 1;
-    PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-  }
-  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
-  }
-  ptr += sizeof(TagType);  // Consume tag
-  if (hasbit_idx < 32) {
-    hasbits |= (uint64_t{1} << hasbit_idx);
-  }
-
-  auto tmp =
-      ParseFallbackPair<uint64_t>(ptr, static_cast<int8_t>(data.data >> 8));
-  data.data = 0;  // Indicate to the compiler that we don't need this anymore.
-  ptr = tmp.first;
-  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
-  }
-
-  RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV32S1(PROTOBUF_TC_PARAM_DECL) {
-  using TagType = uint8_t;
-  // super-early success test...
-  if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
-    ptr += sizeof(TagType);  // Consume tag
-    if (hasbit_idx < 32) {
-      hasbits |= (uint64_t{1} << hasbit_idx);
-    }
-    uint8_t value = data.data >> 8;
-    RefAt<FieldType>(msg, data_offset) = value;
-    ptr += 1;
-    PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-  }
-  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
-  }
-  ptr += sizeof(TagType);  // Consume tag
-  if (hasbit_idx < 32) {
-    hasbits |= (uint64_t{1} << hasbit_idx);
-  }
-
-  auto tmp =
-      ParseFallbackPair<uint32_t>(ptr, static_cast<int8_t>(data.data >> 8));
-  data.data = 0;  // Indicate to the compiler that we don't need this anymore.
-  ptr = tmp.first;
-  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
-  }
-
-  RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
 // Dispatch to the designated parse function
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
-    PROTOBUF_TC_PARAM_DECL) {
+    PROTOBUF_TC_PARAM_NO_DATA_DECL) {
   const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
   const size_t idx = coded_tag & table->fast_idx_mask;
   PROTOBUF_ASSUME((idx & 7) == 0);
   auto* fast_entry = table->fast_entry(idx >> 3);
-  data = fast_entry->bits;
+  TcFieldData data = fast_entry->bits;
   data.data ^= coded_tag;
   PROTOBUF_MUSTTAIL return fast_entry->target()(PROTOBUF_TC_PARAM_PASS);
 }
@@ -992,25 +731,23 @@
 // mode. Luckily the structure of the algorithm is such that it's always
 // possible to just return and use the enclosing parse loop as a trampoline.
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
-    PROTOBUF_TC_PARAM_DECL) {
+    PROTOBUF_TC_PARAM_NO_DATA_DECL) {
   constexpr bool always_return = !PROTOBUF_TAILCALL;
   if (always_return || !ctx->DataAvailable(ptr)) {
-    PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
-  PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
-    PROTOBUF_TC_PARAM_DECL) {
-  (void)data;
+    PROTOBUF_TC_PARAM_NO_DATA_DECL) {
   (void)ctx;
   SyncHasbits(msg, hasbits, table);
   return ptr;
 }
 
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
-    PROTOBUF_TC_PARAM_DECL) {
-  (void)data;
+    PROTOBUF_TC_PARAM_NO_DATA_DECL) {
   (void)ctx;
   (void)ptr;
   SyncHasbits(msg, hasbits, table);
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index 86d067b..1455a9e 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -98,7 +98,7 @@
     // TODO(b/64614992): remove this asm
     asm("" : "+r"(table));
 #endif
-    ptr = TagDispatch(msg, ptr, ctx, {}, table - 1, 0);
+    ptr = TagDispatch(msg, ptr, ctx, TcFieldData::DefaultInit(), table - 1, 0);
     if (ptr == nullptr) break;
     if (ctx->LastTag() != 1) break;  // Ended on terminating tag
   }
@@ -279,7 +279,7 @@
   ptr = ReadTagInlined(ptr, &tag);
   if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
     if (export_called_function) *test_out = {Error};
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
 
   auto* entry = FindFieldEntry(table, tag >> 3);
@@ -351,8 +351,9 @@
   PROTOBUF_MUSTTAIL return parse_fn(PROTOBUF_TC_PARAM_PASS);
 }
 
-PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_PASS);
+PROTOBUF_NOINLINE const char* TcParser::MiniParse(
+    PROTOBUF_TC_PARAM_NO_DATA_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 PROTOBUF_NOINLINE TcParser::TestMiniParseResult TcParser::TestMiniParse(
     PROTOBUF_TC_PARAM_DECL) {
@@ -369,11 +370,11 @@
 template <typename TagType>
 const char* TcParser::FastEndGroupImpl(PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   ctx->SetLastTag(data.decoded_tag());
   ptr += sizeof(TagType);
-  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastEndG1(PROTOBUF_TC_PARAM_DECL) {
@@ -403,7 +404,7 @@
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   auto saved_tag = UnalignedLoad<TagType>(ptr);
   ptr += sizeof(TagType);
@@ -478,7 +479,7 @@
 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedParseMessageAuxImpl(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   const auto expected_tag = UnalignedLoad<TagType>(ptr);
   const auto aux = *table->field_aux(data.aux_idx());
@@ -502,14 +503,14 @@
       }
     }
     if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
     if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) {
-      PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   } while (UnalignedLoad<TagType>(ptr) == expected_tag);
 
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastMdR1(PROTOBUF_TC_PARAM_DECL) {
@@ -560,13 +561,13 @@
 PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
   hasbits |= (uint64_t{1} << data.hasbit_idx());
   RefAt<LayoutType>(msg, data.offset()) = UnalignedLoad<LayoutType>(ptr);
   ptr += sizeof(LayoutType);
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
@@ -598,7 +599,7 @@
     if (data.coded_tag<TagType>() == 0) {
       return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
@@ -607,7 +608,7 @@
     field.Add(UnalignedLoad<LayoutType>(ptr + sizeof(TagType)));
     ptr += sizeof(TagType) + sizeof(LayoutType);
   } while (ctx->DataAvailable(ptr) && UnalignedLoad<TagType>(ptr) == tag);
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
@@ -643,7 +644,7 @@
     if (data.coded_tag<TagType>() == 0) {
       return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   ptr += sizeof(TagType);
@@ -680,6 +681,136 @@
 
 namespace {
 
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
+                                                                uint64_t ones) {
+  return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
+}
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
+// put the new value in res.  Return whether the result was negative.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
+    uint64_t byte, uint64_t ones, int64_t& res) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+  // For the first two rounds (up to 2 varint bytes), micro benchmarks show a
+  // substantial improvement from capturing the sign from the condition code
+  // register on x86-64.
+  bool sign_bit;
+  asm("shldq %3, %2, %1"
+      : "=@ccs"(sign_bit), "+r"(byte)
+      : "r"(ones), "i"(n * 7));
+  res = static_cast<int64_t>(byte);
+  return sign_bit;
+#else
+  // Generic fallback:
+  res = shift_left_fill_with_ones<n>(byte, ones);
+  return res < 0;
+#endif
+}
+
+template <class VarintType>
+inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
+ParseFallbackPair(const char* p, int64_t res1) {
+  constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
+  constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
+  static_assert(kIs64BitVarint || kIs32BitVarint,
+                "Only 32 or 64 bit varints are supported");
+  auto ptr = reinterpret_cast<const int8_t*>(p);
+
+  // The algorithm relies on sign extension for each byte to set all high bits
+  // when the varint continues. It also relies on asserting all of the lower
+  // bits for each successive byte read. This allows the result to be aggregated
+  // using a bitwise AND. For example:
+  //
+  //          8       1          64     57 ... 24     17  16      9  8       1
+  // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111  1111 1111  1aaa aaaa
+  // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111  11bb bbbb  b111 1111
+  // ptr[2] = 0ccc cccc ; res3 = 0000 0000 ... 000c cccc  cc11 1111  1111 1111
+  //                             ---------------------------------------------
+  //        res1 & res2 & res3 = 0000 0000 ... 000c cccc  ccbb bbbb  baaa aaaa
+  //
+  // On x86-64, a shld from a single register filled with enough 1s in the high
+  // bits can accomplish all this in one instruction. It so happens that res1
+  // has 57 high bits of ones, which is enough for the largest shift done.
+  //
+  // Just as importantly, by keeping results in res1, res2, and res3, we take
+  // advantage of the superscalar abilities of the CPU.
+  ABSL_DCHECK_EQ(res1 >> 7, -1);
+  uint64_t ones = res1;  // save the high 1 bits from res1 (input to SHLD)
+  int64_t res2, res3;    // accumulated result chunks
+
+  if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
+    goto done2;
+  if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
+    goto done3;
+
+  // For the remainder of the chunks, check the sign of the AND result.
+  res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
+  if (res2 >= 0) goto done4;
+  res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
+  if (res1 >= 0) goto done5;
+  if (kIs64BitVarint) {
+    res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
+    if (res2 >= 0) goto done6;
+    res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
+    if (res3 >= 0) goto done7;
+    res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
+    if (res1 >= 0) goto done8;
+    res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
+    if (res3 >= 0) goto done9;
+  } else if (kIs32BitVarint) {
+    if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
+    if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
+    if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
+    if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
+  }
+
+  // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
+  // case, the continuation bit of ptr[8] already set the top bit of res3
+  // correctly, so all we have to do is check that the expected case is true.
+  if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
+
+  if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
+    // If the continue bit is set, it is an unterminated varint.
+    return {nullptr, 0};
+  }
+
+  // A zero value of the first bit of the 10th byte represents an
+  // over-serialized varint. This case should not happen, but if does (say, due
+  // to a nonconforming serializer), deassert the continuation bit that came
+  // from ptr[8].
+  if (kIs64BitVarint && (ptr[9] & 1) == 0) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+    // Use a small instruction since this is an uncommon code path.
+    asm("btcq $63,%0" : "+r"(res3));
+#else
+    res3 ^= static_cast<uint64_t>(1) << 63;
+#endif
+  }
+  goto done10;
+
+done2:
+  return {p + 2, res1 & res2};
+done3:
+  return {p + 3, res1 & res2 & res3};
+done4:
+  return {p + 4, res1 & res2 & res3};
+done5:
+  return {p + 5, res1 & res2 & res3};
+done6:
+  return {p + 6, res1 & res2 & res3};
+done7:
+  return {p + 7, res1 & res2 & res3};
+done8:
+  return {p + 8, res1 & res2 & res3};
+done9:
+  return {p + 9, res1 & res2 & res3};
+done10:
+  return {p + 10, res1 & res2 & res3};
+}
+
 template <typename Type>
 inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
                                                       Type* value) {
@@ -792,7 +923,7 @@
 PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
   hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -807,7 +938,7 @@
 
   RefAt<FieldType>(msg, data.offset()) =
       ZigZagDecodeHelper<FieldType, zigzag>(static_cast<uint8_t>(*ptr++));
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 template <typename FieldType, typename TagType, bool zigzag>
@@ -842,31 +973,86 @@
   hasbits = spill.hasbits;
 
   if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   RefAt<FieldType>(msg, data.offset()) =
       ZigZagDecodeHelper<FieldType, zigzag>(tmp);
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+}
+
+template <typename FieldType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::FastVarintS1(
+    PROTOBUF_TC_PARAM_DECL) {
+  using TagType = uint8_t;
+  // super-early success test...
+  if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
+    ptr += sizeof(TagType);  // Consume tag
+    hasbits |= (uint64_t{1} << data.hasbit_idx());
+    uint8_t value = data.data >> 8;
+    RefAt<FieldType>(msg, data.offset()) = value;
+    ptr += 1;
+    PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
+  ptr += sizeof(TagType);  // Consume tag
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+  auto tmp =
+      ParseFallbackPair<FieldType>(ptr, static_cast<int8_t>(data.data >> 8));
+  ptr = tmp.first;
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
+
+  RefAt<FieldType>(msg, data.offset()) = tmp.second;
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return FastTV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS);
+  using TagType = uint8_t;
+
+  // Special case for a varint bool field with a tag of 1 byte:
+  // The coded_tag() field will actually contain the value too and we can check
+  // both at the same time.
+  auto coded_tag = data.coded_tag<uint16_t>();
+  if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
+    auto& field = RefAt<bool>(msg, data.offset());
+    // Note: we use `data.data` because Clang generates suboptimal code when
+    // using coded_tag.
+    // In x86_64 this uses the CH register to read the second byte out of
+    // `data`.
+    uint8_t value = data.data >> 8;
+    // The assume allows using a mov instead of test+setne.
+    PROTOBUF_ASSUME(value <= 1);
+    field = static_cast<bool>(value);
+
+    ptr += sizeof(TagType) + 1;  // Consume the tag and the value.
+    hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+    PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
+
+  // If it didn't match above either the tag is wrong, or the value is encoded
+  // non-canonically.
+  // Jump to MiniParse as wrong tag is the most probable reason.
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
+
 PROTOBUF_NOINLINE const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
   PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
       PROTOBUF_TC_PARAM_PASS);
 }
 PROTOBUF_NOINLINE const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
-      PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return FastVarintS1<uint32_t>(PROTOBUF_TC_PARAM_PASS);
 }
 PROTOBUF_NOINLINE const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
   PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
       PROTOBUF_TC_PARAM_PASS);
 }
 PROTOBUF_NOINLINE const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
-      PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return FastVarintS1<uint64_t>(PROTOBUF_TC_PARAM_PASS);
 }
 PROTOBUF_NOINLINE const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
   PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
@@ -899,7 +1085,7 @@
     if (data.coded_tag<TagType>() == 0) {
       return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
@@ -909,14 +1095,14 @@
     FieldType tmp;
     ptr = ParseVarint(ptr, &tmp);
     if (ptr == nullptr) {
-      return Error(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
     field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
     if (!ctx->DataAvailable(ptr)) {
       break;
     }
   } while (UnalignedLoad<TagType>(ptr) == expected_tag);
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
@@ -969,7 +1155,7 @@
     if (data.coded_tag<TagType>() == 0) {
       return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   ptr += sizeof(TagType);
@@ -1044,7 +1230,7 @@
   uint32_t tag;
   ptr = ReadTag(ptr, &tag);
   if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   data.data = tag;
   PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -1054,14 +1240,14 @@
 PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   const char* ptr2 = ptr;  // Save for unknown enum case
   ptr += sizeof(TagType);  // Consume tag
   uint64_t tmp;
   ptr = ParseVarint(ptr, &tmp);
   if (ptr == nullptr) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
   if (PROTOBUF_PREDICT_FALSE(
@@ -1071,7 +1257,7 @@
   }
   hasbits |= (uint64_t{1} << data.hasbit_idx());
   RefAt<int32_t>(msg, data.offset()) = tmp;
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
@@ -1099,7 +1285,7 @@
       PROTOBUF_MUSTTAIL return PackedEnum<TagType, xform_val>(
           PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1111,7 +1297,7 @@
     uint64_t tmp;
     ptr = ParseVarint(ptr, &tmp);
     if (ptr == nullptr) {
-      return Error(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
     if (PROTOBUF_PREDICT_FALSE(
             !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
@@ -1125,7 +1311,7 @@
       break;
     }
   } while (UnalignedLoad<TagType>(ptr) == expected_tag);
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 const TcParser::UnknownFieldOps& TcParser::GetUnknownFieldOps(
@@ -1153,7 +1339,7 @@
       PROTOBUF_MUSTTAIL return RepeatedEnum<TagType, xform_val>(
           PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   const auto saved_tag = UnalignedLoad<TagType>(ptr);
@@ -1210,18 +1396,18 @@
 PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnumSmallRange(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
 
   uint8_t v = ptr[sizeof(TagType)];
   if (PROTOBUF_PREDICT_FALSE(min > v || v > data.aux_idx())) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
 
   RefAt<int32_t>(msg, data.offset()) = v;
   ptr += sizeof(TagType) + 1;
   hasbits |= (uint64_t{1} << data.hasbit_idx());
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastEr0S1(PROTOBUF_TC_PARAM_DECL) {
@@ -1252,7 +1438,7 @@
       PROTOBUF_MUSTTAIL return PackedEnumSmallRange<TagType, min>(
           PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1261,14 +1447,14 @@
   do {
     uint8_t v = ptr[sizeof(TagType)];
     if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
     field.Add(static_cast<int32_t>(v));
     ptr += sizeof(TagType) + 1;
     if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) break;
   } while (UnalignedLoad<TagType>(ptr) == expected_tag);
 
-  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastEr0R1(PROTOBUF_TC_PARAM_DECL) {
@@ -1297,7 +1483,7 @@
       PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange<TagType, min>(
           PROTOBUF_TC_PARAM_PASS);
     } else {
-      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     }
   }
 
@@ -1387,7 +1573,7 @@
 PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   auto saved_tag = UnalignedLoad<TagType>(ptr);
   ptr += sizeof(TagType);
@@ -1400,20 +1586,24 @@
   } else {
     ptr = ReadStringNoArena(msg, ptr, ctx, data.aux_idx(), table, field);
   }
-  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+  if (ptr == nullptr) {
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
   switch (utf8) {
     case kNoUtf8:
 #ifdef NDEBUG
     case kUtf8ValidateOnly:
 #endif
-      return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
     default:
       if (PROTOBUF_PREDICT_TRUE(IsValidUTF8(field))) {
-        return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+        PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
       }
       ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
-      return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
-                           : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+      if (utf8 == kUtf8) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
+      PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
 }
 
@@ -1447,49 +1637,49 @@
 // Inlined string variants:
 
 const char* TcParser::FastBiS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastBiS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastSiS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastSiS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastUiS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastUiS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 // Corded string variants:
 const char* TcParser::FastBcS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastBcS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastScS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastScS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastUcS1(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 const char* TcParser::FastUcS2(PROTOBUF_TC_PARAM_DECL) {
-  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 template <typename TagType, typename FieldType, TcParser::Utf8Type utf8>
 PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
     PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
   const auto expected_tag = UnalignedLoad<TagType>(ptr);
   auto& field = RefAt<FieldType>(msg, data.offset());
@@ -1522,7 +1712,7 @@
       ptr = ParseRepeatedStringOnce(ptr, arena, serial_arena, ctx, field);
 
       if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
-        return Error(PROTOBUF_TC_PARAM_PASS);
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
       }
       if (!ctx->DataAvailable(ptr)) break;
     } while (UnalignedLoad<TagType>(ptr) == expected_tag);
@@ -1532,12 +1722,12 @@
       std::string* str = field.Add();
       ptr = InlineGreedyStringParser(str, ptr, ctx);
       if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
-        return Error(PROTOBUF_TC_PARAM_PASS);
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
       }
       if (!ctx->DataAvailable(ptr)) break;
     } while (UnalignedLoad<TagType>(ptr) == expected_tag);
   }
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
@@ -1712,7 +1902,7 @@
     RefAt<uint32_t>(base, entry.offset) = UnalignedLoad<uint32_t>(ptr);
     ptr += sizeof(uint32_t);
   }
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::MpRepeatedFixed(
@@ -1761,7 +1951,7 @@
     } while (next_tag == decoded_tag);
   }
 
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
@@ -1790,9 +1980,9 @@
   }
 
   if (ptr == nullptr) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 template <bool is_split>
@@ -1817,7 +2007,9 @@
   const char* ptr2 = ptr;  // save for unknown enum case
   uint64_t tmp;
   ptr = ParseVarint(ptr, &tmp);
-  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+  if (ptr == nullptr) {
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+  }
 
   // Transform and/or validate the value
   uint16_t rep = type_card & field_layout::kRepMask;
@@ -1854,7 +2046,7 @@
     RefAt<bool>(base, entry.offset) = static_cast<bool>(tmp);
   }
 
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
@@ -1884,11 +2076,15 @@
     do {
       uint64_t tmp;
       ptr = ParseVarint(ptr2, &tmp);
-      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
       field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
       if (!ctx->DataAvailable(ptr)) break;
       ptr2 = ReadTag(ptr, &next_tag);
-      if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr2 == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
     } while (next_tag == decoded_tag);
   } else if (rep == field_layout::kRep32Bits) {
     auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
@@ -1897,7 +2093,9 @@
     do {
       uint64_t tmp;
       ptr = ParseVarint(ptr2, &tmp);
-      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
       if (is_validated_enum) {
         if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
           ptr = ptr2;
@@ -1909,7 +2107,9 @@
       field.Add(tmp);
       if (!ctx->DataAvailable(ptr)) break;
       ptr2 = ReadTag(ptr, &next_tag);
-      if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr2 == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
     } while (next_tag == decoded_tag);
   } else {
     ABSL_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
@@ -1919,15 +2119,19 @@
     do {
       uint64_t tmp;
       ptr = ParseVarint(ptr2, &tmp);
-      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
       field.Add(static_cast<bool>(tmp));
       if (!ctx->DataAvailable(ptr)) break;
       ptr2 = ReadTag(ptr, &next_tag);
-      if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (ptr2 == nullptr) {
+        PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+      }
     } while (next_tag == decoded_tag);
   }
 
-  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
@@ -1978,7 +2182,7 @@
         ptr, [field](uint64_t value) { field->Add(value); });
   }
 
-  return Error(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes,
@@ -2056,9 +2260,9 @@
   }
 
   if (ptr == nullptr || !is_valid) {
-    return Error(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
   }
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 PROTOBUF_ALWAYS_INLINE const char* TcParser::ParseRepeatedStringOnce(
@@ -2105,7 +2309,7 @@
           if (PROTOBUF_PREDICT_FALSE(ptr == nullptr ||
                                      !MpVerifyUtf8(field[field.size() - 1],
                                                    table, entry, xform_val))) {
-            return Error(PROTOBUF_TC_PARAM_PASS);
+            PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
           }
           if (!ctx->DataAvailable(ptr)) break;
           ptr2 = ReadTag(ptr, &next_tag);
@@ -2118,7 +2322,7 @@
           if (PROTOBUF_PREDICT_FALSE(
                   ptr == nullptr ||
                   !MpVerifyUtf8(*str, table, entry, xform_val))) {
-            return Error(PROTOBUF_TC_PARAM_PASS);
+            PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
           }
           if (!ctx->DataAvailable(ptr)) break;
           ptr2 = ReadTag(ptr, &next_tag);
@@ -2135,7 +2339,7 @@
 #endif
   }
 
-  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
 }
 
 template <bool is_split>
diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc
index e242d83..12aeced 100644
--- a/src/google/protobuf/generated_message_tctable_lite_test.cc
+++ b/src/google/protobuf/generated_message_tctable_lite_test.cc
@@ -94,7 +94,7 @@
   const TcParseTable<0, 1, 0, 0, 2> parse_table = {
       {
           kHasBitsOffset,  //
-          0, 0, 0,         // no _extensions_
+          0,               // no _extensions_
           1, 0,            // max_field_number, fast_idx_mask
           offsetof(decltype(parse_table), field_lookup_table),
           0xFFFFFFFF - 1,  // skipmap
@@ -125,7 +125,7 @@
   // clang-format on
   uint8_t serialize_buffer[64];
 
-  for (int size : {8, 32, 64, -8, -32, -64}) {
+  for (int size : {8, 32, 64}) {
     SCOPED_TRACE(size);
     auto next_i = [](uint64_t i) {
       // if i + 1 is a power of two, return that.
@@ -192,21 +192,12 @@
           case 8:
             fn = &TcParser::FastV8S1;
             break;
-          case -8:
-            fn = &TcParser::FastTV8S1<kFieldOffset, kHasBitIndex>;
-            break;
           case 32:
             fn = &TcParser::FastV32S1;
             break;
-          case -32:
-            fn = &TcParser::FastTV32S1<uint32_t, kFieldOffset, kHasBitIndex>;
-            break;
           case 64:
             fn = &TcParser::FastV64S1;
             break;
-          case -64:
-            fn = &TcParser::FastTV64S1<uint64_t, kFieldOffset, kHasBitIndex>;
-            break;
         }
         fallback_ptr_received = absl::nullopt;
         fallback_hasbits_received = absl::nullopt;
@@ -215,7 +206,6 @@
                      Xor2SerializedBytes(parse_table.fast_entries[0].bits, ptr),
                      &parse_table.header, /*hasbits=*/0);
         switch (size) {
-          case -8:
           case 8: {
             if (end_ptr == nullptr) {
               // If end_ptr is nullptr, that means the FastParser gave up and
@@ -240,7 +230,6 @@
             EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i))  //
                 << " hex: " << absl::StrCat(absl::Hex(actual_field));
           }; break;
-          case -32:
           case 32: {
             ASSERT_TRUE(end_ptr);
             ASSERT_EQ(end_ptr - ptr, serialized.size());
@@ -249,7 +238,6 @@
             EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i))  //
                 << " hex: " << absl::StrCat(absl::Hex(actual_field));
           }; break;
-          case -64:
           case 64: {
             ASSERT_EQ(end_ptr - ptr, serialized.size());
 
@@ -297,9 +285,9 @@
   TcParseTable<0, 3, 0, 0, 2> table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          0,           // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          0,     // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF - 7,  // 7 = fields 1, 2, and 3.
           offsetof(decltype(table), field_names),
@@ -364,9 +352,9 @@
   TcParseTable<0, 5, 0, 0, 8> table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          111,         // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          111,   // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF - (1 << 1) - (1 << 2)   // fields 2, 3
                      - (1 << 3) - (1 << 4),  // fields 4, 5
@@ -405,9 +393,9 @@
   TcParseTable<0, 6, 0, 0, 8> table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          111,         // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          111,   // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) - (1<<6),  // 1,3-5,7
           offsetof(decltype(table), field_entries),
@@ -451,9 +439,9 @@
   TcParseTable<0, 10, 0, 0, 8> table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          70,          // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          70,    // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4)   // 1, 3, 4, 5, 6
                      - (1<<5) - (1<<7) - (1<<8) - (1<<10)  // 8, 9, 11, 12
@@ -497,9 +485,9 @@
   TcParseTable<0, 3, 0, 15, 2> table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          3,           // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          3,     // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF - (1<<0) - (1<<1) - (1<<2),  // fields 1, 2, 3
           offsetof(decltype(table), field_entries),
@@ -547,9 +535,9 @@
   TableType table = {
       // header:
       {
-          0, 0, 0, 0,  // has_bits_offset, extensions
-          0,           // max_field_number
-          0,           // fast_idx_mask,
+          0, 0,  // has_bits_offset, extensions
+          0,     // max_field_number
+          0,     // fast_idx_mask,
           offsetof(decltype(table), field_lookup_table),
           0xFFFFFFFF,       // no fields
           offsetof(decltype(table), field_names),  // no field_entries
@@ -598,7 +586,7 @@
 const TcParseTable<5, 134, 5, 2176, 55> test_all_types_table = {
     // header:
     {
-        0, 0, 0, 0,  // has_bits_offset, extensions
+        0, 0,  // has_bits_offset, extensions
         418, 248,    // max_field_number, fast_idx_mask
         offsetof(decltype(test_all_types_table), field_lookup_table),
         977895424,  // skipmap for fields 1-15,18-19,21-22,24-25,27,31-32
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
index 204da69..c41d8b3 100644
--- a/src/google/protobuf/message_unittest.inc
+++ b/src/google/protobuf/message_unittest.inc
@@ -1166,6 +1166,31 @@
             std::signbit(out_message.optional_double()));
 }
 
+TEST(MESSAGE_TEST_NAME,
+     RegressionTestForParseMessageReadingUninitializedLimit) {
+  UNITTEST::TestAllTypes in_message;
+  in_message.mutable_optional_nested_message();
+  std::string serialized = in_message.SerializeAsString();
+  // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+  // Break the size by making it overlong.
+  ASSERT_EQ(serialized.size(), 3);
+  serialized.back() = '\200';
+  serialized += std::string(10, '\200');
+  EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME,
+     RegressionTestForParseMessageWithSizeBeyondInputFailsToPopLimit) {
+  UNITTEST::TestAllTypes in_message;
+  in_message.mutable_optional_nested_message();
+  std::string serialized = in_message.SerializeAsString();
+  // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+  // Make the size a valid varint, but it overflows in the input.
+  ASSERT_EQ(serialized.size(), 3);
+  serialized.back() = 10;
+  EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
 const uint8_t* SkipTag(const uint8_t* buf) {
   while (*buf & 0x80) ++buf;
   ++buf;
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index 11d2181..b96e7ac 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -319,26 +319,19 @@
 }
 
 const char* ParseContext::ReadSizeAndPushLimitAndDepth(const char* ptr,
-                                                       int* old_limit) {
-  int size = ReadSize(&ptr);
-  if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
-    *old_limit = 0;  // Make sure this isn't uninitialized even on error return
-    return nullptr;
-  }
-  *old_limit = PushLimit(ptr, size);
-  --depth_;
-  return ptr;
+                                                       LimitToken* old_limit) {
+  return ReadSizeAndPushLimitAndDepthInlined(ptr, old_limit);
 }
 
 const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
-  int old;
+  LimitToken old;
   ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
   if (ptr == nullptr) return ptr;
   auto old_depth = depth_;
   ptr = msg->_InternalParse(ptr, this);
   if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
   depth_++;
-  if (!PopLimit(old)) return nullptr;
+  if (!PopLimit(std::move(old))) return nullptr;
   return ptr;
 }
 
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index e5b13a0..0ddaa26 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -36,11 +36,13 @@
 #include <string>
 #include <type_traits>
 
+#include "absl/base/config.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
 #include "absl/strings/cord.h"
 #include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
 #include "google/protobuf/arena.h"
 #include "google/protobuf/arenastring.h"
 #include "google/protobuf/endian.h"
@@ -131,8 +133,53 @@
     if (count > 0) StreamBackUp(count);
   }
 
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
+  // In sanitizer mode we use an optional<int> to guarantee that:
+  //  - We do not read an uninitialized token.
+  //  - Every non-empty token is moved from and consumed.
+  class LimitToken {
+   public:
+    LimitToken() = default;
+    explicit LimitToken(int token) : token_(token) {}
+    LimitToken(LimitToken&& other) { *this = std::move(other); }
+    LimitToken& operator=(LimitToken&& other) {
+      token_ = std::exchange(other.token_, absl::nullopt);
+      return *this;
+    }
+
+    ~LimitToken() { ABSL_CHECK(!token_.has_value()); }
+
+    LimitToken(const LimitToken&) = delete;
+    LimitToken& operator=(const LimitToken&) = delete;
+
+    int token() && {
+      ABSL_CHECK(token_.has_value());
+      return *std::exchange(token_, absl::nullopt);
+    }
+
+   private:
+    absl::optional<int> token_;
+  };
+#else
+  class LimitToken {
+   public:
+    LimitToken() = default;
+    explicit LimitToken(int token) : token_(token) {}
+    LimitToken(LimitToken&&) = default;
+    LimitToken& operator=(LimitToken&&) = default;
+
+    LimitToken(const LimitToken&) = delete;
+    LimitToken& operator=(const LimitToken&) = delete;
+
+    int token() const { return token_; }
+
+   private:
+    int token_;
+  };
+#endif
+
   // If return value is negative it's an error
-  PROTOBUF_NODISCARD int PushLimit(const char* ptr, int limit) {
+  PROTOBUF_NODISCARD LimitToken PushLimit(const char* ptr, int limit) {
     ABSL_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
     // This add is safe due to the invariant above, because
     // ptr - buffer_end_ <= kSlopBytes.
@@ -140,12 +187,14 @@
     limit_end_ = buffer_end_ + (std::min)(0, limit);
     auto old_limit = limit_;
     limit_ = limit;
-    return old_limit - limit;
+    return LimitToken(old_limit - limit);
   }
 
-  PROTOBUF_NODISCARD bool PopLimit(int delta) {
+  PROTOBUF_NODISCARD bool PopLimit(LimitToken delta) {
+    // We must update the limit first before the early return. Otherwise, we can
+    // end up with an invalid limit and it can lead to integer overflows.
+    limit_ = limit_ + std::move(delta).token();
     if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
-    limit_ = limit_ + delta;
     // TODO(gerbens) We could remove this line and hoist the code to
     // DoneFallback. Study the perf/bin-size effects.
     limit_end_ = buffer_end_ + (std::min)(0, limit_);
@@ -470,13 +519,14 @@
   template <typename TcParser, typename Table>
   PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
       MessageLite* msg, const char* ptr, const Table* table) {
-    int old;
+    LimitToken old;
     ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
+    if (ptr == nullptr) return ptr;
     auto old_depth = depth_;
-    ptr = ptr ? TcParser::ParseLoop(msg, ptr, this, table) : nullptr;
+    ptr = TcParser::ParseLoop(msg, ptr, this, table);
     if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
     depth_++;
-    if (!PopLimit(old)) return nullptr;
+    if (!PopLimit(std::move(old))) return nullptr;
     return ptr;
   }
 
@@ -518,20 +568,20 @@
 
  private:
   // Out-of-line routine to save space in ParseContext::ParseMessage<T>
-  //   int old;
+  //   LimitToken old;
   //   ptr = ReadSizeAndPushLimitAndDepth(ptr, &old)
   // is equivalent to:
   //   int size = ReadSize(&ptr);
   //   if (!ptr) return nullptr;
-  //   int old = PushLimit(ptr, size);
+  //   LimitToken old = PushLimit(ptr, size);
   //   if (--depth_ < 0) return nullptr;
-  PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
-                                                              int* old_limit);
+  PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(
+      const char* ptr, LimitToken* old_limit);
 
   // As above, but fully inlined for the cases where we care about performance
   // more than size. eg TcParser.
   PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
-  ReadSizeAndPushLimitAndDepthInlined(const char* ptr, int* old_limit);
+  ReadSizeAndPushLimitAndDepthInlined(const char* ptr, LimitToken* old_limit);
 
   // The context keeps an internal stack to keep track of the recursive
   // part of the parse state.
@@ -881,27 +931,25 @@
                           !std::is_base_of<MessageLite, T>::value, bool>::type>
 PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
                                                           const char* ptr) {
-  int old;
+  LimitToken old;
   ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
   if (ptr == nullptr) return ptr;
   auto old_depth = depth_;
   ptr = msg->_InternalParse(ptr, this);
   if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
   depth_++;
-  if (!PopLimit(old)) return nullptr;
+  if (!PopLimit(std::move(old))) return nullptr;
   return ptr;
 }
 
 inline const char* ParseContext::ReadSizeAndPushLimitAndDepthInlined(
-    const char* ptr, int* old_limit) {
+    const char* ptr, LimitToken* old_limit) {
   int size = ReadSize(&ptr);
-  if (PROTOBUF_PREDICT_FALSE(!ptr)) {
-    // Make sure this isn't uninitialized even on error return
-    *old_limit = 0;
+  if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
     return nullptr;
   }
   *old_limit = PushLimit(ptr, size);
-  if (--depth_ < 0) return nullptr;
+  --depth_;
   return ptr;
 }
 
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index ef458ad..35df77a 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -856,6 +856,19 @@
 // PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
 #define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, data, table, hasbits
 
+// PROTOBUF_TC_PARAM_NO_DATA_DECL and PROTOBUF_TC_PARAM_NO_DATA_PASS provide the
+// exact same ABI as above, except that they don't name or pass the `data`
+// argument. Specific functions such as `Error() and `ToTagDispatch()` don't
+// use the `data` argument. By not passing `data` down the call stack, we free
+// up the register holding that value, which may matter in highly optimized
+// functions such as varint parsing.
+#define PROTOBUF_TC_PARAM_NO_DATA_DECL                                        \
+  ::google::protobuf::MessageLite *msg, const char *ptr,                                \
+      ::google::protobuf::internal::ParseContext *ctx, ::google::protobuf::internal::TcFieldData, \
+      const ::google::protobuf::internal::TcParseTableBase *table, uint64_t hasbits
+#define PROTOBUF_TC_PARAM_NO_DATA_PASS \
+  msg, ptr, ctx, ::google::protobuf::internal::TcFieldData::DefaultInit(), table, hasbits
+
 #ifdef PROTOBUF_UNUSED
 #error PROTOBUF_UNUSED was previously defined
 #endif
@@ -1014,6 +1027,13 @@
 //   int index = ...
 //   int value = vec[index];
 #pragma GCC diagnostic ignored "-Wsign-conversion"
+#if __GNUC__ == 12 && __GNUC_MINOR__ < 4
+// Wrong warning emitted when assigning a single char c-string to a std::string
+// in c++20 mode and optimization on.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
+// Planned to be fixed by 12.3 but widen window to 12.4.
+#pragma GCC diagnostic ignored "-Wrestrict"
+#endif
 #endif  // __GNUC__
 
 // Silence some MSVC warnings in all our code.
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index e723394..67b6b3d 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -46,6 +46,7 @@
 #include "google/protobuf/testing/googletest.h"
 #include <gtest/gtest.h>
 #include "absl/container/flat_hash_set.h"
+#include "absl/functional/bind_front.h"
 #include "absl/strings/cord.h"
 #include "absl/synchronization/mutex.h"
 #include "absl/time/clock.h"